From 6a52823216814d71d103e0eb9d08ed3a595362c5 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 25 Apr 2024 18:09:31 +0100 Subject: [PATCH 01/70] Add a rule and check for empty paragraphs --- src/pageScanner/checks/paragraph-not-empty.js | 19 +++++++++++++++++++ .../rules/paragraph-should-not-be-empty.js | 16 ++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/pageScanner/checks/paragraph-not-empty.js create mode 100644 src/pageScanner/rules/paragraph-should-not-be-empty.js diff --git a/src/pageScanner/checks/paragraph-not-empty.js b/src/pageScanner/checks/paragraph-not-empty.js new file mode 100644 index 00000000..62ffed06 --- /dev/null +++ b/src/pageScanner/checks/paragraph-not-empty.js @@ -0,0 +1,19 @@ +/** + * Check if a paragraph is empty. + * + * @param {Node} node The paragraph element to evaluate. + * @return {boolean} Returns true if the paragraph is empty, false otherwise. + */ + +export default { + id: 'paragraph_not_empty', + evaluate: ( node ) => { + // if not a paragraph this immediately passes. + if ( 'p' !== node.tagName.toLowerCase() ) { + return true; + } + + // if the paragraph has text content it is a pass, otherwise it is a fail. + return !! node.textContent.trim(); + }, +}; diff --git a/src/pageScanner/rules/paragraph-should-not-be-empty.js b/src/pageScanner/rules/paragraph-should-not-be-empty.js new file mode 100644 index 00000000..a090cba5 --- /dev/null +++ b/src/pageScanner/rules/paragraph-should-not-be-empty.js @@ -0,0 +1,16 @@ +export default { + id: 'paragraph_should_not_be_empty', + selector: 'p', + excludeHidden: false, + tags: [ + 'cat.text', + ], + impact: 'moderate', + metadata: { + description: 'Detects empty paragraph tags', + help: 'Paragraphs should not be used for layout purposes and should never be empty', + }, + all: [], + any: [ 'paragraph_not_empty' ], + none: [], +}; From c17e9c029a01ad4d525ee1779d81bceacc52c220 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 25 Apr 2024 18:11:17 +0100 Subject: [PATCH 02/70] Run the check for empty paragraphs in JS page scanner --- src/pageScanner/index.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/pageScanner/index.js b/src/pageScanner/index.js index d1961e51..ddddccdd 100644 --- a/src/pageScanner/index.js +++ b/src/pageScanner/index.js @@ -3,6 +3,9 @@ import 'axe-core'; import colorContrastFailure from './rules/color-contrast-failure'; +import paragraphShouldNotBeEmpty from './rules/paragraph-should-not-be-empty'; +import paragraphNotEmpty from './checks/paragraph-not-empty'; + //TODO: examples: //import customRule1 from './rules/custom-rule-1'; //import alwaysFail from './checks/always-fail'; @@ -35,16 +38,24 @@ const scan = async ( rules: [ //customRule1, colorContrastFailure, + paragraphShouldNotBeEmpty, ], checks: [ //alwaysFail, + paragraphNotEmpty, ], iframes: false, }, resultTypes: [ 'violations' ], runOptions: { - runOnly: [ 'color_contrast_failure' ], + runOnly: { + type: 'rule', + values: [ + 'color_contrast_failure', + 'paragraph_should_not_be_empty', + ], + }, /* //TODO: From fc819adefc3166379dd46e500267608c751b53bd Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 25 Apr 2024 19:14:24 +0100 Subject: [PATCH 03/70] Use the id direct from the import to avoid needing to write a string in 2 places --- src/pageScanner/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pageScanner/index.js b/src/pageScanner/index.js index ddddccdd..ac778729 100644 --- a/src/pageScanner/index.js +++ b/src/pageScanner/index.js @@ -52,8 +52,8 @@ const scan = async ( runOnly: { type: 'rule', values: [ - 'color_contrast_failure', - 'paragraph_should_not_be_empty', + colorContrastFailure.id, + paragraphShouldNotBeEmpty.id, ], }, From d533bab7c650891f71e86d29b1af5c39c0d2ad3a Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 26 Apr 2024 15:23:49 +0100 Subject: [PATCH 04/70] Add the empty paragraph rule to rules array --- includes/rules.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/includes/rules.php b/includes/rules.php index cfa83ffb..cc5b01b8 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -74,6 +74,14 @@ '<h2>' ), ), + array( + 'title' => esc_html__( 'Empty Paragraph Tags', 'accessibility-checker' ), + 'info_url' => 'https://a11ychecker.com/help###', + 'slug' => 'paragraph_should_not_be_empty', + 'rule_type' => 'error', + 'summary' => esc_html__( 'Paragraph tags that are empty get announced to screen readers with empty content creating unnecessary noise. Paragraphs should never be used for layout purposes.', 'accessibility-checker' ), + 'ruleset' => 'js', + ), array( 'title' => esc_html__( 'iFrame Missing Title', 'accessibility-checker' ), 'info_url' => 'https://a11ychecker.com/help1953', From 7b75beacd89ea1753f079b7ad074d8827387ce33 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 26 Apr 2024 15:29:22 +0100 Subject: [PATCH 05/70] Add a filter to make empty paragraph html unique --- includes/classes/class-rest-api.php | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/includes/classes/class-rest-api.php b/includes/classes/class-rest-api.php index 5049b9ff..54f3f068 100644 --- a/includes/classes/class-rest-api.php +++ b/includes/classes/class-rest-api.php @@ -32,6 +32,7 @@ public function __construct() { */ public function init_hooks() { add_action( 'init', array( $this, 'init_rest_routes' ) ); + add_filter( 'edac_filter_js_violation_html', 'filter_js_validation_html', 10, 3 ); } @@ -161,7 +162,27 @@ function () use ( $ns, $version ) { ); } - + /** + * Filter the html of the js validation violation. + * + * This can be used to store additional data in the html of the violation. + * + * @param string $html The html of the violation. + * @param string $rule_id The id of the rule. + * @param array $violation The violation data. + * + * @return string + */ + public function filter_js_validation_html( string $html, string $rule_id, array $violation ): string { + // Add the selector to the violation message as empty paragraphs are almost always + // duplicate html fragments. Adding the selector makes it unique, so it can be saved. + if ( 'paragraph_should_not_be_empty' === $rule_id ) { + $html .= $violation['selector'][0] + ? '// {{ ' . $violation['selector'][0] . ' }}' + : ''; + } + return $html; + } /** * REST handler that saves to the DB a list of js rule violations for a post. @@ -220,7 +241,7 @@ public function set_post_scan_results( $request ) { // This rule is one that we've included in our js ruleset. - $html = $violation['html']; + $html = apply_filters( 'edac_filter_js_violation_html', $violation['html'], $rule_id, $violation ); $impact = $violation['impact']; // by default, use the impact setting from the js rule. //phpcs:ignore Generic.Commenting.Todo.TaskFound From abf8b96876216a79d272bc496b385c435992332b Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 26 Apr 2024 18:49:51 +0100 Subject: [PATCH 06/70] Add error for zoom disabled via viewport meta tag This will flag an error if user-scalable is set to 'no' or if the maximum-scale is lower than 2 --- includes/rules.php | 8 ++++++++ src/pageScanner/index.js | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/includes/rules.php b/includes/rules.php index cfa83ffb..a8b29bfe 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -419,4 +419,12 @@ '<a>' ), ), + array( + 'title' => esc_html__( 'Zooming and scaling is disabled', 'accessibility-checker' ), + 'info_url' => 'https://a11ychecker.com/help###', + 'slug' => 'meta-viewport', + 'rule_type' => 'error', + 'summary' => esc_html__( 'Zooming is disabled via viewport meta tag that includes `user-scalable=no` or a `maximum-scale` value of less than 2. This limits low-vision users that want to increase text sizes, zoom into the page or who use a magnifier.', 'accessibility-checker' ), + 'ruleset' => 'js', + ), ); diff --git a/src/pageScanner/index.js b/src/pageScanner/index.js index d1961e51..da6a46ef 100644 --- a/src/pageScanner/index.js +++ b/src/pageScanner/index.js @@ -44,7 +44,13 @@ const scan = async ( }, resultTypes: [ 'violations' ], runOptions: { - runOnly: [ 'color_contrast_failure' ], + runOnly: { + type: 'rule', + values: [ + 'color_contrast_failure', + 'meta-viewport', + ], + }, /* //TODO: From ca54ed4eb1d80297c577870642ee2ead7d5b4c3b Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 14 May 2024 14:39:27 +0100 Subject: [PATCH 07/70] Make empty paragraph a warning --- includes/rules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/rules.php b/includes/rules.php index cc5b01b8..deceb410 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -78,7 +78,7 @@ 'title' => esc_html__( 'Empty Paragraph Tags', 'accessibility-checker' ), 'info_url' => 'https://a11ychecker.com/help###', 'slug' => 'paragraph_should_not_be_empty', - 'rule_type' => 'error', + 'rule_type' => 'warning', 'summary' => esc_html__( 'Paragraph tags that are empty get announced to screen readers with empty content creating unnecessary noise. Paragraphs should never be used for layout purposes.', 'accessibility-checker' ), 'ruleset' => 'js', ), From e1a5d0bf9003d6871b4783166d42482a7775c0b3 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 14 May 2024 14:39:47 +0100 Subject: [PATCH 08/70] Fix filter to use method from inside the class --- includes/classes/class-rest-api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/classes/class-rest-api.php b/includes/classes/class-rest-api.php index 54f3f068..02ad7bdc 100644 --- a/includes/classes/class-rest-api.php +++ b/includes/classes/class-rest-api.php @@ -32,7 +32,7 @@ public function __construct() { */ public function init_hooks() { add_action( 'init', array( $this, 'init_rest_routes' ) ); - add_filter( 'edac_filter_js_violation_html', 'filter_js_validation_html', 10, 3 ); + add_filter( 'edac_filter_js_violation_html', array( $this, 'filter_js_validation_html' ), 10, 3 ); } From e0ac1c598fdc6f92939f09999cdc5a78614e8df1 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 14 May 2024 14:42:54 +0100 Subject: [PATCH 09/70] Use singular form for title and update the summary text Also make the link not hit a 404 or other unexpected page, point just to the root --- includes/rules.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/rules.php b/includes/rules.php index deceb410..7a686921 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -75,11 +75,11 @@ ), ), array( - 'title' => esc_html__( 'Empty Paragraph Tags', 'accessibility-checker' ), - 'info_url' => 'https://a11ychecker.com/help###', + 'title' => esc_html__( 'Empty Paragraph Tag', 'accessibility-checker' ), + 'info_url' => 'https://a11ychecker.com/', 'slug' => 'paragraph_should_not_be_empty', 'rule_type' => 'warning', - 'summary' => esc_html__( 'Paragraph tags that are empty get announced to screen readers with empty content creating unnecessary noise. Paragraphs should never be used for layout purposes.', 'accessibility-checker' ), + 'summary' => esc_html__( 'An Empty Paragraph Tag error means there is a paragraph tag present that does not contain content. These may be announced by screen readers and create unnecessary noise for blind users. To fix this error, remove the empty paragraphs from the page. If you need to add spacing between sections, this should be done with padding, margins, or a spacer block.', 'accessibility-checker' ), 'ruleset' => 'js', ), array( From 437f45d7bae3d65aae2a05d21928bf6ababe4085 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 14 May 2024 22:06:08 +0100 Subject: [PATCH 10/70] Add a rule and check file for detection paragraphs that are possible headings --- .../checks/paragraph-styled-as-header.js | 40 +++++++++++++++++++ src/pageScanner/rules/possible-heading.js | 15 +++++++ 2 files changed, 55 insertions(+) create mode 100644 src/pageScanner/checks/paragraph-styled-as-header.js create mode 100644 src/pageScanner/rules/possible-heading.js diff --git a/src/pageScanner/checks/paragraph-styled-as-header.js b/src/pageScanner/checks/paragraph-styled-as-header.js new file mode 100644 index 00000000..6c82fa56 --- /dev/null +++ b/src/pageScanner/checks/paragraph-styled-as-header.js @@ -0,0 +1,40 @@ +/** + * Axe core check for elements with text content over x characters. + * + * @param {Node} node The node to evaluate. + * @return {boolean} True if the node has text content longer than x characters, false otherwise. + */ + +export default { + id: 'paragraph_styled_as_header', + evaluate: ( node ) => { + const text = node.textContent.trim(); + const pixelSize = parseFloat( window.getComputedStyle( node ).fontSize ); + + // long paragraphs or with size under 16px are unlikely to be headers. + if ( text.length > 50 || pixelSize <= 16 ) { + return false; + } + + // paragraphs that are 20px or more are probably headers. + if ( pixelSize >= 20 ) { + return true; + } + + const style = window.getComputedStyle( node ); + const fontWeight = style.getPropertyValue( 'font-weight' ); + const isBold = [ 'bold', 'bolder', '700', '800', '900' ].includes( fontWeight ); + + const fontStyle = style.getPropertyValue( 'font-style' ); + const isItalic = [ 'italic', 'oblique' ].includes( fontStyle ); + + const hasBoldOrItalicTag = node.querySelector( 'b, strong, i, em' ) !== null; + + if ( isBold || isItalic || hasBoldOrItalicTag ) { + return true; + } + + // didn't find anything indicating this is a possible header. + return false; + }, +}; diff --git a/src/pageScanner/rules/possible-heading.js b/src/pageScanner/rules/possible-heading.js new file mode 100644 index 00000000..25cf8e09 --- /dev/null +++ b/src/pageScanner/rules/possible-heading.js @@ -0,0 +1,15 @@ +export default { + id: 'possible_heading', + selector: 'p', + excludeHidden: false, + tags: [ + 'cat.text', + ], + metadata: { + description: 'Headings should be used to convey the structure of the page, not styled paragraphs', + help: 'Paragraphs should not be styled to look like headings. Use the appropriate heading tag instead.', + }, + all: [], + any: [], + none: [ 'paragraph_styled_as_header' ], +}; From 8187628c274bfda986f956540e464640623d1484 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 14 May 2024 22:06:34 +0100 Subject: [PATCH 11/70] Include the possible_heading rule in the page scanner --- src/pageScanner/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pageScanner/index.js b/src/pageScanner/index.js index 30ca8ed7..1d7ddb6a 100644 --- a/src/pageScanner/index.js +++ b/src/pageScanner/index.js @@ -6,6 +6,8 @@ import colorContrastFailure from './rules/color-contrast-failure'; import underlinedText from './rules/underlined-text'; import elementWithUnderline from './checks/element-with-underline'; import elementIsAUTag from './checks/element-is-u-tag'; +import possibleHeading from './rules/possible-heading'; +import paragraphStyledAsHeader from './checks/paragraph-styled-as-header'; //TODO: examples: //import customRule1 from './rules/custom-rule-1'; @@ -40,11 +42,13 @@ const scan = async ( // customRule1, colorContrastFailure, underlinedText, + possibleHeading, ], checks: [ //alwaysFail, elementIsAUTag, elementWithUnderline, + paragraphStyledAsHeader, ], iframes: false, @@ -56,6 +60,7 @@ const scan = async ( values: [ 'color_contrast_failure', 'underlined_text', + possibleHeading.id, ], }, From 0d5ade22b05f9c0850805b9562eef7735a893ed3 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 14 May 2024 22:07:22 +0100 Subject: [PATCH 12/70] Make the possible_heading rule use the js ruleset --- includes/rules.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/rules.php b/includes/rules.php index 287d7ef7..4b98634a 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -322,6 +322,7 @@ 'slug' => 'possible_heading', 'rule_type' => 'warning', 'summary' => esc_html__( 'A Possible Heading warning occurs when there is text on a page that appears to be a heading, but has not been coded with proper heading tags. This warning is appears if there are short phrases or strings of text less than 50 characters in length that are formatted in a way which suggests they might be being used as headers (they are 20 pixels or bigger, or are 16 pixels or bigger and bold and/or italicized). To fix a Possible Heading warning, you will need to determine if the flagged text is indeed intended to be a heading. If so, you need to change it from a paragraph to a heading at the proper level. If it is not supposed to be a heading then you can safely “Ignore” the warning.', 'accessibility-checker' ), + 'ruleset' => 'js', ], [ 'title' => esc_html__( 'Blinking or Scrolling Content', 'accessibility-checker' ), From e9bb54414d9ebfe2574f957a6b9f2419c95d0987 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 14 May 2024 22:08:20 +0100 Subject: [PATCH 13/70] Remove the possible_heading.php file as it is replaced by JS --- includes/rules/possible_heading.php | 152 ---------------------------- 1 file changed, 152 deletions(-) delete mode 100644 includes/rules/possible_heading.php diff --git a/includes/rules/possible_heading.php b/includes/rules/possible_heading.php deleted file mode 100644 index aaed8367..00000000 --- a/includes/rules/possible_heading.php +++ /dev/null @@ -1,152 +0,0 @@ - element contains less than 50 characters and is either: - * 20 pixels or bigger, or - * 16 pixels or bigger and bold and/or italicized. - */ -function edac_rule_possible_heading( $content, $post ) { // phpcs:ignore -- $post is reserved for future use or for compliance with a specific interface. - - $dom = $content['html']; - $errors = []; - - /* - * check for inline styles - *

Possible Heading

- *

Possible Heading

- *

Possible Heading

- *

Possible Heading

- *

Possible Heading

- *

Possible Heading

- *

Possible Heading

- */ - $fontsearchpatterns = []; - $fontsearchpatterns[] = '|font\-size:\s?([\d]+)pt|i'; - $fontsearchpatterns[] = '|font\-size:\s?([\d]+)px|i'; - $fontsearchpatterns[] = '|font:\s?[\w\s\d*\s]*([\d]+)pt|i'; - $fontsearchpatterns[] = '|font:\s?[\w\s\d*\s]*([\d]+)px|i'; - - $elements = $dom->find( 'p' ); - if ( $elements ) { - foreach ( $elements as $element ) { - - if ( isset( $element ) && '' !== $element->innertext && strlen( $element->innertext ) < 50 ) { - - // parse inline styles and run logic. - $styles = $element->getAttribute( 'style' ); - $css_array = edac_parse_css( $styles ); - if ( $css_array ) { - foreach ( $css_array as $rules ) { - - if ( array_key_exists( 'font-size', $rules ) ) { - - if ( preg_match( '(rem|em|%|inherit)', $rules['font-size'] ) === 1 ) { - continue; } - - if ( $rules['font-size'] >= 20 ) { - $errors[] = $element; - } elseif ( $rules['font-size'] >= 16 ) { - - if ( - preg_match( '(bold|bolder|700|800|900)', stristr( $element->getAttribute( 'style' ), 'font-weight:' ) ) === 1 || - preg_match( '(italic|oblique)', stristr( $element->getAttribute( 'style' ), 'font-style:' ) ) === 1 || - $element->find( 'b' ) || - $element->find( 'strong' ) || - $element->find( 'i' ) || - $element->find( 'em' ) - ) { - $errors[] = $element; - } - } - } - } - } - } - } - } - - // check styles. - if ( $content['css_parsed'] ) { - $errors = array_merge( edac_css_font_size_weight_check( $content ), $errors ); - } - - return $errors; -} - -/** - * CSS Font Size Weight Check - * - * @param obj $content to be checked. - * @return array - */ -function edac_css_font_size_weight_check( $content ) { - $dom = $content['html']; - $errors = []; - $css_array = $content['css_parsed']; - - if ( $css_array ) { - foreach ( $css_array as $element => $rules ) { - $add_error = false; - - if ( array_key_exists( 'font-size', $rules ) ) { - // replace CSS variables. - $rules['font-size'] = edac_replace_css_variables( $rules['font-size'], $css_array ); - - if ( preg_match( '(rem|em|%|inherit)', $rules['font-size'] ) !== 1 ) { - if ( $rules['font-size'] >= 20 ) { - $add_error = true; - } elseif ( $rules['font-size'] >= 16 ) { - $has_bold_or_italic = false; - if ( array_key_exists( 'font-weight', $rules ) ) { - // replace CSS variables. - $rules['font-weight'] = edac_replace_css_variables( $rules['font-weight'], $css_array ); - if ( in_array( $rules['font-weight'], [ 'bold', 'bolder', '700', '800', '900' ], true ) ) { - $has_bold_or_italic = true; - } - } - if ( array_key_exists( 'font-style', $rules ) ) { - // replace CSS variables. - $rules['font-style'] = edac_replace_css_variables( $rules['font-style'], $css_array ); - if ( 'italic' === $rules['font-style'] || 'oblique' === $rules['font-style'] ) { - $has_bold_or_italic = true; - } - } - if ( $has_bold_or_italic ) { - $add_error = true; - } - } - } - - if ( $add_error ) { - $error_code = $element . '{ '; - foreach ( $rules as $key => $value ) { - $error_code .= $key . ': ' . $value . '; '; - } - $error_code .= '}'; - - $elements = $dom->find( $element ); - if ( $elements ) { - foreach ( $elements as $element ) { - if ( 'p' === $element->tag && strlen( $element->innertext ) < 50 ) { - $errors[] = $element->outertext . ' ' . $error_code; - } - } - } - } - } - } - } - - return $errors; -} From 88e3a612c9894c9615262e88fbf9c3d5b0e5c609 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 15 May 2024 15:40:38 +0100 Subject: [PATCH 14/70] Use 'empty_paragraph' as the slug for new rule --- includes/classes/class-rest-api.php | 2 +- includes/rules.php | 2 +- src/pageScanner/index.js | 6 +++--- ...{paragraph-should-not-be-empty.js => empty-paragraph.js} | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename src/pageScanner/rules/{paragraph-should-not-be-empty.js => empty-paragraph.js} (89%) diff --git a/includes/classes/class-rest-api.php b/includes/classes/class-rest-api.php index 02ad7bdc..62e2ed44 100644 --- a/includes/classes/class-rest-api.php +++ b/includes/classes/class-rest-api.php @@ -176,7 +176,7 @@ function () use ( $ns, $version ) { public function filter_js_validation_html( string $html, string $rule_id, array $violation ): string { // Add the selector to the violation message as empty paragraphs are almost always // duplicate html fragments. Adding the selector makes it unique, so it can be saved. - if ( 'paragraph_should_not_be_empty' === $rule_id ) { + if ( 'empty_paragraph' === $rule_id ) { $html .= $violation['selector'][0] ? '// {{ ' . $violation['selector'][0] . ' }}' : ''; diff --git a/includes/rules.php b/includes/rules.php index 7a686921..7b4937e8 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -77,7 +77,7 @@ array( 'title' => esc_html__( 'Empty Paragraph Tag', 'accessibility-checker' ), 'info_url' => 'https://a11ychecker.com/', - 'slug' => 'paragraph_should_not_be_empty', + 'slug' => 'empty_paragraph', 'rule_type' => 'warning', 'summary' => esc_html__( 'An Empty Paragraph Tag error means there is a paragraph tag present that does not contain content. These may be announced by screen readers and create unnecessary noise for blind users. To fix this error, remove the empty paragraphs from the page. If you need to add spacing between sections, this should be done with padding, margins, or a spacer block.', 'accessibility-checker' ), 'ruleset' => 'js', diff --git a/src/pageScanner/index.js b/src/pageScanner/index.js index ac778729..c532ea1f 100644 --- a/src/pageScanner/index.js +++ b/src/pageScanner/index.js @@ -3,7 +3,7 @@ import 'axe-core'; import colorContrastFailure from './rules/color-contrast-failure'; -import paragraphShouldNotBeEmpty from './rules/paragraph-should-not-be-empty'; +import emptyParagraph from './rules/empty-paragraph'; import paragraphNotEmpty from './checks/paragraph-not-empty'; //TODO: examples: @@ -38,7 +38,7 @@ const scan = async ( rules: [ //customRule1, colorContrastFailure, - paragraphShouldNotBeEmpty, + emptyParagraph, ], checks: [ //alwaysFail, @@ -53,7 +53,7 @@ const scan = async ( type: 'rule', values: [ colorContrastFailure.id, - paragraphShouldNotBeEmpty.id, + emptyParagraph.id, ], }, diff --git a/src/pageScanner/rules/paragraph-should-not-be-empty.js b/src/pageScanner/rules/empty-paragraph.js similarity index 89% rename from src/pageScanner/rules/paragraph-should-not-be-empty.js rename to src/pageScanner/rules/empty-paragraph.js index a090cba5..b2e843e4 100644 --- a/src/pageScanner/rules/paragraph-should-not-be-empty.js +++ b/src/pageScanner/rules/empty-paragraph.js @@ -1,5 +1,5 @@ export default { - id: 'paragraph_should_not_be_empty', + id: 'empty_paragraph', selector: 'p', excludeHidden: false, tags: [ From 102cbe49369e9b1d3f78606f0680d0379ac7d5ac Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 15 May 2024 15:43:17 +0100 Subject: [PATCH 15/70] Use 'empty_paragraph_tag' as the slug for new rule --- includes/classes/class-rest-api.php | 2 +- includes/rules.php | 4 ++-- src/pageScanner/rules/empty-paragraph.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/includes/classes/class-rest-api.php b/includes/classes/class-rest-api.php index 62e2ed44..0351d0d7 100644 --- a/includes/classes/class-rest-api.php +++ b/includes/classes/class-rest-api.php @@ -176,7 +176,7 @@ function () use ( $ns, $version ) { public function filter_js_validation_html( string $html, string $rule_id, array $violation ): string { // Add the selector to the violation message as empty paragraphs are almost always // duplicate html fragments. Adding the selector makes it unique, so it can be saved. - if ( 'empty_paragraph' === $rule_id ) { + if ( 'empty_paragraph_tag' === $rule_id ) { $html .= $violation['selector'][0] ? '// {{ ' . $violation['selector'][0] . ' }}' : ''; diff --git a/includes/rules.php b/includes/rules.php index 7b4937e8..b937db8c 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -77,9 +77,9 @@ array( 'title' => esc_html__( 'Empty Paragraph Tag', 'accessibility-checker' ), 'info_url' => 'https://a11ychecker.com/', - 'slug' => 'empty_paragraph', + 'slug' => 'empty_paragraph_tag', 'rule_type' => 'warning', - 'summary' => esc_html__( 'An Empty Paragraph Tag error means there is a paragraph tag present that does not contain content. These may be announced by screen readers and create unnecessary noise for blind users. To fix this error, remove the empty paragraphs from the page. If you need to add spacing between sections, this should be done with padding, margins, or a spacer block.', 'accessibility-checker' ), + 'summary' => esc_html__( 'An Empty Paragraph Tag warning means there is a paragraph tag present that does not contain content. These may be announced by screen readers or create confusion for users. To fix this warning, remove the empty paragraphs from the page. If you need to add spacing between sections, this should be done with padding, margins, or a spacer block.', 'accessibility-checker' ), 'ruleset' => 'js', ), array( diff --git a/src/pageScanner/rules/empty-paragraph.js b/src/pageScanner/rules/empty-paragraph.js index b2e843e4..26aa8f4d 100644 --- a/src/pageScanner/rules/empty-paragraph.js +++ b/src/pageScanner/rules/empty-paragraph.js @@ -1,5 +1,5 @@ export default { - id: 'empty_paragraph', + id: 'empty_paragraph_tag', selector: 'p', excludeHidden: false, tags: [ From 93856d9a0d182bcc836df99fd9084c993042a830 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 15 May 2024 15:43:45 +0100 Subject: [PATCH 16/70] Add best practices tag to new empty paragraphs rule --- src/pageScanner/rules/empty-paragraph.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pageScanner/rules/empty-paragraph.js b/src/pageScanner/rules/empty-paragraph.js index 26aa8f4d..d0f5825a 100644 --- a/src/pageScanner/rules/empty-paragraph.js +++ b/src/pageScanner/rules/empty-paragraph.js @@ -4,6 +4,7 @@ export default { excludeHidden: false, tags: [ 'cat.text', + 'best-practices', ], impact: 'moderate', metadata: { From c0e957685fe0656f30885089b3369533a7a27428 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Mon, 20 May 2024 19:03:03 +0100 Subject: [PATCH 17/70] Update paragraph_not_empty check to pass elements with no text content if they have child elements. --- src/pageScanner/checks/paragraph-not-empty.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/pageScanner/checks/paragraph-not-empty.js b/src/pageScanner/checks/paragraph-not-empty.js index 62ffed06..54dd3540 100644 --- a/src/pageScanner/checks/paragraph-not-empty.js +++ b/src/pageScanner/checks/paragraph-not-empty.js @@ -1,19 +1,26 @@ /** - * Check if a paragraph is empty. + * Check that a paragraph is NOT empty. * * @param {Node} node The paragraph element to evaluate. - * @return {boolean} Returns true if the paragraph is empty, false otherwise. + * @return {boolean} Returns true if the paragraph has content, false if empty. */ export default { id: 'paragraph_not_empty', evaluate: ( node ) => { - // if not a paragraph this immediately passes. if ( 'p' !== node.tagName.toLowerCase() ) { return true; } - // if the paragraph has text content it is a pass, otherwise it is a fail. - return !! node.textContent.trim(); + // if there are child nodes then it passes. + if ( node.childNodes.length ) { + return true; + } + + if ( node.textContent.trim() !== '' ) { + return true; + } + + return false; }, }; From 1bcda56456fb60163a197a226e708892bf293375 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Mon, 20 May 2024 19:05:38 +0100 Subject: [PATCH 18/70] Simplify the final return in paragraph_not_empty --- src/pageScanner/checks/has-text-docoration.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/pageScanner/checks/has-text-docoration.js diff --git a/src/pageScanner/checks/has-text-docoration.js b/src/pageScanner/checks/has-text-docoration.js new file mode 100644 index 00000000..e69de29b From 2aee26496f10636518f3e3dd5e6ab62cd58053d8 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Mon, 20 May 2024 19:13:27 +0100 Subject: [PATCH 19/70] Simplify the final return in paragraph_not_empty --- src/pageScanner/checks/paragraph-not-empty.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pageScanner/checks/paragraph-not-empty.js b/src/pageScanner/checks/paragraph-not-empty.js index 54dd3540..6a7b965f 100644 --- a/src/pageScanner/checks/paragraph-not-empty.js +++ b/src/pageScanner/checks/paragraph-not-empty.js @@ -17,10 +17,7 @@ export default { return true; } - if ( node.textContent.trim() !== '' ) { - return true; - } - - return false; + // if there is text content then it passes, false otherwise. + return node.textContent.trim() !== ''; }, }; From ddb578f4f7b384995d76351de794eb25bb397c91 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Mon, 20 May 2024 22:13:58 +0100 Subject: [PATCH 20/70] Improve comment in paragraph-styled-as-header.js check --- .../checks/paragraph-styled-as-header.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/pageScanner/checks/paragraph-styled-as-header.js b/src/pageScanner/checks/paragraph-styled-as-header.js index 6c82fa56..9b0a82c3 100644 --- a/src/pageScanner/checks/paragraph-styled-as-header.js +++ b/src/pageScanner/checks/paragraph-styled-as-header.js @@ -1,8 +1,18 @@ /** - * Axe core check for elements with text content over x characters. + * Check for elements with text content that is styled like a header. + * + * Axe-core has a built-in `p-as-heading` rule that checks for paragraphs + * that are styled like headings. That rule is less robust than this check, + * as it only checks for paragraphs with bold or italic text and gives back + * 'incomplete' or uncertain results for some of the test data that we want + * to flag for further checks. + * + * This check in this file takes into account the font size, length of the + * text, and considers paragraphs with large font size as headers as well. * * @param {Node} node The node to evaluate. - * @return {boolean} True if the node has text content longer than x characters, false otherwise. + * @return {boolean} True if the node is styled like a header, false otherwise. Paragraphs with only bold or italic, + * are shorter than 50 characters, or are short with large font size are considered headers. */ export default { @@ -22,6 +32,7 @@ export default { } const style = window.getComputedStyle( node ); + const fontWeight = style.getPropertyValue( 'font-weight' ); const isBold = [ 'bold', 'bolder', '700', '800', '900' ].includes( fontWeight ); From 45f435c00be84792d0b2181b07d34093ea7cf6ff Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 21 May 2024 14:20:23 +0100 Subject: [PATCH 21/70] Add a helpers file with a fontSizeInPxxx function --- src/pageScanner/helpers/helpers.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/pageScanner/helpers/helpers.js diff --git a/src/pageScanner/helpers/helpers.js b/src/pageScanner/helpers/helpers.js new file mode 100644 index 00000000..7c16e66f --- /dev/null +++ b/src/pageScanner/helpers/helpers.js @@ -0,0 +1,7 @@ +export const fontSizeInPx = ( node ) => { + if ( node === null || node === 'undefined' || node.nodeType !== Node.ELEMENT_NODE ) { + return 0; + } + + return parseFloat( window.getComputedStyle( node ).fontSize ); +}; From 3580bf7a15c6e812eb8f06c0cc83d5ab3982d80f Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 21 May 2024 14:25:05 +0100 Subject: [PATCH 22/70] Use new fontSizeInPx helper --- src/pageScanner/checks/paragraph-styled-as-header.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pageScanner/checks/paragraph-styled-as-header.js b/src/pageScanner/checks/paragraph-styled-as-header.js index 9b0a82c3..8f0ee1c3 100644 --- a/src/pageScanner/checks/paragraph-styled-as-header.js +++ b/src/pageScanner/checks/paragraph-styled-as-header.js @@ -15,14 +15,15 @@ * are shorter than 50 characters, or are short with large font size are considered headers. */ +import { fontSizeInPx } from '../helpers/helpers.js'; + export default { id: 'paragraph_styled_as_header', evaluate: ( node ) => { - const text = node.textContent.trim(); - const pixelSize = parseFloat( window.getComputedStyle( node ).fontSize ); + const pixelSize = fontSizeInPx( node ); // long paragraphs or with size under 16px are unlikely to be headers. - if ( text.length > 50 || pixelSize <= 16 ) { + if ( node.textContent.trim().length > 50 || pixelSize <= 16 ) { return false; } From b02dc508aafb8679d623b7c988244aaa17f22830 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 21 May 2024 15:10:45 +0100 Subject: [PATCH 23/70] Use < 16px in first return so that everything after it is 16px or more. --- src/pageScanner/checks/paragraph-styled-as-header.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pageScanner/checks/paragraph-styled-as-header.js b/src/pageScanner/checks/paragraph-styled-as-header.js index 8f0ee1c3..c299cb15 100644 --- a/src/pageScanner/checks/paragraph-styled-as-header.js +++ b/src/pageScanner/checks/paragraph-styled-as-header.js @@ -23,7 +23,7 @@ export default { const pixelSize = fontSizeInPx( node ); // long paragraphs or with size under 16px are unlikely to be headers. - if ( node.textContent.trim().length > 50 || pixelSize <= 16 ) { + if ( node.textContent.trim().length > 50 || pixelSize < 16 ) { return false; } From 552f2e673c479e9808ec415157b78c256e7f26fa Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 21 May 2024 14:20:23 +0100 Subject: [PATCH 24/70] Add a helpers file with a fontSizeInPxxx function --- src/pageScanner/helpers/helpers.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/pageScanner/helpers/helpers.js diff --git a/src/pageScanner/helpers/helpers.js b/src/pageScanner/helpers/helpers.js new file mode 100644 index 00000000..7c16e66f --- /dev/null +++ b/src/pageScanner/helpers/helpers.js @@ -0,0 +1,7 @@ +export const fontSizeInPx = ( node ) => { + if ( node === null || node === 'undefined' || node.nodeType !== Node.ELEMENT_NODE ) { + return 0; + } + + return parseFloat( window.getComputedStyle( node ).fontSize ); +}; From 06ccfce8a0d2e68bec86d2db4588861de6d2900e Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 14:13:44 +0100 Subject: [PATCH 25/70] Add a check for small text of 10px or less --- src/pageScanner/checks/text-size-too-small.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/pageScanner/checks/text-size-too-small.js diff --git a/src/pageScanner/checks/text-size-too-small.js b/src/pageScanner/checks/text-size-too-small.js new file mode 100644 index 00000000..5bf09a25 --- /dev/null +++ b/src/pageScanner/checks/text-size-too-small.js @@ -0,0 +1,18 @@ +/** + * Axe core check against nodes to determine if the text size is too small. + * + * @param {Node} node The node to evaluate. + * @return {boolean} True if the text size is equal to or below the minimum size. False otherwise. + */ + +import { fontSizeInPx } from '../helpers/helpers'; + +const SMALL_FONT_SIZE_THRESHOLD = 10; + +export default { + id: 'text_size_too_small', + evaluate: ( node ) => { + // fails if the font size is less than or equal to 10px. + return fontSizeInPx( node ) <= SMALL_FONT_SIZE_THRESHOLD; + }, +}; From 33420b2e9c664091664a535ae1bb9779d4d4d613 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 14:14:23 +0100 Subject: [PATCH 26/70] Add rule that checks for small text --- src/pageScanner/index.js | 5 +++++ src/pageScanner/rules/text-small.js | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/pageScanner/rules/text-small.js diff --git a/src/pageScanner/index.js b/src/pageScanner/index.js index 30ca8ed7..22d24cbf 100644 --- a/src/pageScanner/index.js +++ b/src/pageScanner/index.js @@ -6,6 +6,8 @@ import colorContrastFailure from './rules/color-contrast-failure'; import underlinedText from './rules/underlined-text'; import elementWithUnderline from './checks/element-with-underline'; import elementIsAUTag from './checks/element-is-u-tag'; +import textSmall from './rules/text-small'; +import textSizeTooSmall from './checks/text-size-too-small'; //TODO: examples: //import customRule1 from './rules/custom-rule-1'; @@ -40,11 +42,13 @@ const scan = async ( // customRule1, colorContrastFailure, underlinedText, + textSmall, ], checks: [ //alwaysFail, elementIsAUTag, elementWithUnderline, + textSizeTooSmall, ], iframes: false, @@ -56,6 +60,7 @@ const scan = async ( values: [ 'color_contrast_failure', 'underlined_text', + textSmall.id, ], }, diff --git a/src/pageScanner/rules/text-small.js b/src/pageScanner/rules/text-small.js new file mode 100644 index 00000000..b88b7b55 --- /dev/null +++ b/src/pageScanner/rules/text-small.js @@ -0,0 +1,22 @@ +/** + * Rule: Text small failure + * + * Text should have a minimum size and anything below that is a fail. + */ + +export default { + id: 'text_small', + impact: 'moderate', + selector: 'p, span, small, strong, b, i, h1, h2, h3, h4, h5, h6, a, label, button, th, td, li, div, blockquote, address, cite, code, pre, q, s, sub, sup, u, var, abbr, acronym, del, dfn, em, ins, kbd, samp, time, mark, meter, progress, ruby, rt, rp, wbr, bdi, bdo, br, hr, img, input, select, textarea, output, video, audio, canvas, map, area, object, embed, param, source, track, iframe, table, caption, col, colgroup, thead, tbody, tfoot, tr, th, td, dl, dt, dd, ol, ul, menu, dir, li, figure, figcaption, main, header, footer, nav, section, article, aside, details, dialog, summary, data, time, title, style, script, noscript, template', + matches: ( element ) => { + // only run checks on elements with text content + return element.textContent.trim().length; + }, + tags: [ 'cat.text' ], + metadata: { + description: 'Text elements should not be too small.', + }, + all: [], + any: [], + none: [ 'text_size_too_small' ], +}; From 2ce65620487bc4cda41399265ef1a1c8e27896b0 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 14:16:58 +0100 Subject: [PATCH 27/70] Swap the text_small rule to the JS ruleset --- includes/rules.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/rules.php b/includes/rules.php index 287d7ef7..85bdb34f 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -315,6 +315,7 @@ 'slug' => 'text_small', 'rule_type' => 'warning', 'summary' => esc_html__( 'A Text Too Small warning occurs when there is text on your website that is less than 10px in size. The warning is an indication that you may want to rethink the font size and make it larger so that it can be more easily read without a user needing zoom in on their browser. To fix text that is too small, you will need to ensure that all text elements on your website are at least 10 points.', 'accessibility-checker' ), + 'ruleset' => 'js', ], [ 'title' => esc_html__( 'Possible Heading', 'accessibility-checker' ), From 0d6d7a04d39e4dd6fb5e8a4beca2a9f73aaf45c9 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 14:17:55 +0100 Subject: [PATCH 28/70] Remove the text_small.php rule file --- includes/rules/text_small.php | 119 ---------------------------------- 1 file changed, 119 deletions(-) delete mode 100644 includes/rules/text_small.php diff --git a/includes/rules/text_small.php b/includes/rules/text_small.php deleted file mode 100644 index 3a3ef1b6..00000000 --- a/includes/rules/text_small.php +++ /dev/null @@ -1,119 +0,0 @@ -test

- */ - $dom = $content['html']; - $elements = $dom->find( '*' ); - if ( $elements ) { - foreach ( $elements as $element ) { - - if ( isset( $element ) && stristr( $element->getAttribute( 'style' ), 'font-size:' ) && '' !== $element->innertext ) { - - // Get font size. - foreach ( $fontsearchpatterns as $pattern ) { - if ( preg_match_all( $pattern, $element, $matches, PREG_PATTERN_ORDER ) ) { - $matchsize = count( $matches ); - for ( $i = 0; $i < $matchsize; $i++ ) { - if ( isset( $matches[0][ $i ] ) && '' !== $matches[0][ $i ] ) { - $absolute_fontsize_errorcode = htmlspecialchars( $matches[0][ $i ] ); - - preg_match_all( '!\d+!', $absolute_fontsize_errorcode, $matches ); - - if ( - ( - stristr( $absolute_fontsize_errorcode, 'px' ) === 'px' && - implode( ' ', $matches[0] ) <= 10 - ) || ( - ( stristr( $absolute_fontsize_errorcode, 'pt' ) === 'pt' ) && - ( implode( ' ', $matches[0] ) <= 13 ) - ) - ) { - $errors[] = $element; - } - } - } - } - } - } - } - } - - // check styles. - if ( $content['css_parsed'] ) { - $errors = array_merge( ac_css_small_text_check( $content ), $errors ); - } - - return $errors; -} - -/** - * Check for small test in css files - * - * @param obj $content The content. - * @return array - */ -function ac_css_small_text_check( $content ) { - - $dom = $content['html']; - $errors = []; - $error_code = ''; - $css_array = $content['css_parsed']; - - if ( $css_array ) { - foreach ( $css_array as $element => $rules ) { - if ( array_key_exists( 'font-size', $rules ) ) { - - // replace CSS variables. - $rules['font-size'] = edac_replace_css_variables( $rules['font-size'], $css_array ); - - $value = str_replace( '.', '', preg_replace( '/\d/', '', $rules['font-size'] ) ); - - if ( - ( 'px' === $value && $rules['font-size'] <= 10 ) || - ( 'pt' === $value && $rules['font-size'] <= 13 ) - ) { - - $error_code = $element . '{ '; - foreach ( $rules as $key => $value ) { - $error_code .= $key . ': ' . $value . '; '; - } - $error_code .= '}'; - - $elements = $dom->find( $element ); - if ( $elements ) { - foreach ( $elements as $element ) { - if ( 'p' === $element->tag ) { - $errors[] = $element->outertext . ' ' . $error_code; - } - } - } - } - } - } - } - - return $errors; -} From df9e07ff19480a9ceda7af05e6c2fea1ac3c9cca Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 15:23:37 +0100 Subject: [PATCH 29/70] Add a check and rule for checking text_justified rule This is currently setup to align with the description of the php rule, but not necessarily the code of the php rule --- src/pageScanner/checks/text-is-justified.js | 14 ++++++++++++++ src/pageScanner/rules/text-justified.js | 21 +++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/pageScanner/checks/text-is-justified.js create mode 100644 src/pageScanner/rules/text-justified.js diff --git a/src/pageScanner/checks/text-is-justified.js b/src/pageScanner/checks/text-is-justified.js new file mode 100644 index 00000000..07c5b464 --- /dev/null +++ b/src/pageScanner/checks/text-is-justified.js @@ -0,0 +1,14 @@ +/** + * Axe core check for elements that are aligned to justify. + * + * @param {Node} node The node to evaluate. + * @return {boolean} True if the node is justified, false otherwise. + */ + +export default { + id: 'text_is_justified', + evaluate: ( node ) => { + const style = window.getComputedStyle( node ); + return style.textAlign.toLowerCase() === 'justify'; + }, +}; diff --git a/src/pageScanner/rules/text-justified.js b/src/pageScanner/rules/text-justified.js new file mode 100644 index 00000000..389b2ef0 --- /dev/null +++ b/src/pageScanner/rules/text-justified.js @@ -0,0 +1,21 @@ +/** + * Rule: Text Justified + * + * Text elements should not be justified because it interferes with readability. + */ + +const TEXT_JUSTIFIED_CHECK_THRESHOLD = 500; +export default { + id: 'text_justified', + selector: 'p, div, td', + matches: ( element ) => { + return element.textContent.trim().length >= TEXT_JUSTIFIED_CHECK_THRESHOLD; + }, + tags: [ 'wcag2aaa', 'wcag148', 'cat.text', 'custom' ], + metadata: { + description: 'Text elements inside containers should not be justified.', + }, + all: [], + any: [], + none: [ 'text_is_justified' ], +}; From 9d27e68b9d2e6dee762bd878454c0fe2089a578e Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 15:23:59 +0100 Subject: [PATCH 30/70] Swap text_justified to the JS ruleset --- includes/rules.php | 1 + src/pageScanner/index.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/includes/rules.php b/includes/rules.php index 287d7ef7..9b8151f1 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -111,6 +111,7 @@ '<div>', '<td>' ), + 'ruleset' => 'js', ], [ 'title' => esc_html__( 'Link Opens New Window or Tab', 'accessibility-checker' ), diff --git a/src/pageScanner/index.js b/src/pageScanner/index.js index 30ca8ed7..80b2c9b4 100644 --- a/src/pageScanner/index.js +++ b/src/pageScanner/index.js @@ -6,6 +6,8 @@ import colorContrastFailure from './rules/color-contrast-failure'; import underlinedText from './rules/underlined-text'; import elementWithUnderline from './checks/element-with-underline'; import elementIsAUTag from './checks/element-is-u-tag'; +import textJustified from './rules/text-justified'; +import textIsJustified from './checks/text-is-justified'; //TODO: examples: //import customRule1 from './rules/custom-rule-1'; @@ -40,11 +42,13 @@ const scan = async ( // customRule1, colorContrastFailure, underlinedText, + textJustified, ], checks: [ //alwaysFail, elementIsAUTag, elementWithUnderline, + textIsJustified, ], iframes: false, @@ -56,6 +60,7 @@ const scan = async ( values: [ 'color_contrast_failure', 'underlined_text', + textJustified.id, ], }, From 63a08f998042dd394c31af0642036355112b0534 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 15:24:24 +0100 Subject: [PATCH 31/70] Remove the text_justified.php rule file --- includes/rules/text_justified.php | 95 ------------------------------- 1 file changed, 95 deletions(-) delete mode 100644 includes/rules/text_justified.php diff --git a/includes/rules/text_justified.php b/includes/rules/text_justified.php deleted file mode 100644 index c43ebfc4..00000000 --- a/includes/rules/text_justified.php +++ /dev/null @@ -1,95 +0,0 @@ -test - */ - $dom = $content['html']; - $elements = $dom->find( '*' ); - if ( $elements ) { - foreach ( $elements as $element ) { - - if ( isset( $element ) && stristr( $element->getAttribute( 'style' ), 'text-align:' ) && '' !== $element->innertext ) { - - foreach ( $fontsearchpatterns as $pattern ) { - if ( preg_match_all( $pattern, $element, $matches, PREG_PATTERN_ORDER ) ) { - $matchsize = count( $matches ); - for ( $i = 0; $i < $matchsize; $i++ ) { - if ( isset( $matches[0][ $i ] ) && '' !== $matches[0][ $i ] ) { - $errors[] = $element; - } - } - } - } - } - } - } - - // check styles. - if ( $content['css_parsed'] ) { - $errors = array_merge( edac_css_justified_text_check( $content ), $errors ); - } - - return $errors; -} - -/** - * Check for text-align: justify in css files - * - * @param obj $content The object. - * @return array - */ -function edac_css_justified_text_check( $content ) { - - $dom = $content['html']; - $errors = []; - $error_code = ''; - $css_array = $content['css_parsed']; - - if ( $css_array ) { - foreach ( $css_array as $element => $rules ) { - if ( array_key_exists( 'text-align', $rules ) ) { - - // replace CSS variables. - $rules['text-align'] = edac_replace_css_variables( $rules['text-align'], $css_array ); - - $value = preg_replace( '/\d/', '', $rules['text-align'] ); - - if ( 'justify' === $value ) { - - $error_code = $element . '{ '; - foreach ( $rules as $key => $value ) { - $error_code .= $key . ': ' . $value . '; '; - } - $error_code .= '}'; - - $elements = $dom->find( $element ); - if ( $elements ) { - foreach ( $elements as $element ) { - $errors[] = $element->outertext . ' ' . $error_code; - } - } - } - } - } - } - return $errors; -} From bebdaff97874f2374d4fe4a4042359ae3b86201e Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 17:58:12 +0100 Subject: [PATCH 32/70] Enable the blinks and marquee axe-core rules --- src/pageScanner/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pageScanner/index.js b/src/pageScanner/index.js index 30ca8ed7..f43e4e66 100644 --- a/src/pageScanner/index.js +++ b/src/pageScanner/index.js @@ -56,6 +56,8 @@ const scan = async ( values: [ 'color_contrast_failure', 'underlined_text', + 'blink', + 'marquee', ], }, From 0100608a09d6b7aeb3b28c8d7d0f6cfa3ea4fe73 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 18:00:28 +0100 Subject: [PATCH 33/70] Swap text_blinking to the JS ruleset and add a 'combines' item to the definition The combines holds the 2 axe rule ids that are run in the scanner that are both grouped under the one rule ID in the reporting --- includes/rules.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/includes/rules.php b/includes/rules.php index 287d7ef7..263ba275 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -335,6 +335,8 @@ '<marquee>', 'text-decoration: blink' ), + 'ruleset' => 'js', + 'combines' => [ 'blink', 'marquee' ], ], [ 'title' => esc_html__( 'Insufficient Color Contrast', 'accessibility-checker' ), From f5e901d646022da49ddba4beb9449845b17f046b Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 18:02:58 +0100 Subject: [PATCH 34/70] Add some handling for reported rules that are 'combined' from other checks in JS --- includes/classes/class-rest-api.php | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/includes/classes/class-rest-api.php b/includes/classes/class-rest-api.php index e1a93e03..5d54625b 100644 --- a/includes/classes/class-rest-api.php +++ b/includes/classes/class-rest-api.php @@ -161,8 +161,6 @@ function () use ( $ns, $version ) { ); } - - /** * REST handler that saves to the DB a list of js rule violations for a post. * @@ -194,11 +192,18 @@ public function set_post_scan_results( $request ) { //phpcs:ignore Generic.Commenting.Todo.TaskFound // TODO: setup a rules class for loading/filtering rules. - $rules = edac_register_rules(); - $js_rule_ids = []; + $rules = edac_register_rules(); + $js_rule_ids = []; + $combined_rule_ids = []; foreach ( $rules as $rule ) { if ( array_key_exists( 'ruleset', $rule ) && 'js' === $rule['ruleset'] ) { $js_rule_ids[] = $rule['slug']; + + if ( array_key_exists( 'combines', $rule ) && ! empty( $rule['combines'] ) ) { + foreach ( $rule['combines'] as $combine_rule_id ) { + $combined_rule_ids[ $combine_rule_id ] = $rule['slug']; + } + } } } @@ -226,7 +231,9 @@ public function set_post_scan_results( $request ) { foreach ( $violations as $violation ) { $rule_id = $violation['ruleId']; - if ( in_array( $rule_id, $js_rule_ids, true ) ) { + $actual_rule_id = array_key_exists( $rule_id, $combined_rule_ids ) ? $combined_rule_ids[ $rule_id ] : $rule_id; + + if ( in_array( $actual_rule_id, $js_rule_ids, true ) ) { // This rule is one that we've included in our js ruleset. @@ -236,7 +243,7 @@ public function set_post_scan_results( $request ) { //phpcs:ignore Generic.Commenting.Todo.TaskFound // TODO: setup a rules class for loading/filtering rules. foreach ( $rules as $rule ) { - if ( $rule['slug'] === $rule_id ) { + if ( $rule['slug'] === $actual_rule_id ) { $impact = $rule['rule_type']; // if we are defining the rule_type in php rules config, use that instead of the js rule's impact setting. } } @@ -255,9 +262,9 @@ public function set_post_scan_results( $request ) { * @param string $rule_id The rule ID. * @param string $type The type of validation which is always 'js' in this path. */ - do_action( 'edac_before_rule', $post_id, $rule_id, 'js' ); + do_action( 'edac_before_rule', $post_id, $actual_rule_id, 'js' ); - ( new Insert_Rule_Data() )->insert( $post, $rule_id, $impact, $html ); + ( new Insert_Rule_Data() )->insert( $post, $actual_rule_id, $impact, $html ); /** * Fires after a rule is run against the content. @@ -270,7 +277,7 @@ public function set_post_scan_results( $request ) { * @param string $rule_id The rule ID. * @param string $type The type of validation which is always 'js' in this path. */ - do_action( 'edac_after_rule', $post_id, $rule_id, 'js' ); + do_action( 'edac_after_rule', $post_id, $actual_rule_id, 'js' ); } } @@ -297,6 +304,10 @@ public function set_post_scan_results( $request ) { // store a record of this scan in the post's meta. update_post_meta( $post_id, '_edac_post_checked_js', time() ); + if ( true === $request['isFailure'] ) { + update_post_meta( $post_id, '_edac_post_checked_js_failure', time() ); + } + return new \WP_REST_Response( [ 'success' => true, From f452552c7451fbf687552f171fbe4369c1dce2ae Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 18:03:37 +0100 Subject: [PATCH 35/70] Remove the text_blinking_scrolling.php file as it's replaced with an Axe-Core run JavaScript equivalent --- includes/rules/text_blinking_scrolling.php | 100 --------------------- 1 file changed, 100 deletions(-) delete mode 100644 includes/rules/text_blinking_scrolling.php diff --git a/includes/rules/text_blinking_scrolling.php b/includes/rules/text_blinking_scrolling.php deleted file mode 100644 index 3b230d2e..00000000 --- a/includes/rules/text_blinking_scrolling.php +++ /dev/null @@ -1,100 +0,0 @@ -This text may blink depending on the browser you use. - */ - $blinks = $dom->find( 'blink' ); - foreach ( $blinks as $blink ) { - $errors[] = $blink->outertext; - } - - /** - * Check for marquee tag - * This text may scroll from right to left depending on the browser you you. - */ - $marquees = $dom->find( 'marquee' ); - foreach ( $marquees as $marquee ) { - $errors[] = $marquee->outertext; - } - - /** - * Check for text-decoration: blink - *

This text may blink depending on the browser you use.

- */ - $elements = $dom->find( '*' ); - if ( $elements ) { - foreach ( $elements as $element ) { - if ( isset( $element ) && stristr( $element->getAttribute( 'style' ), 'text-decoration:' ) && '' !== $element->innertext ) { - if ( strpos( strtolower( $element ), 'blink' ) ) { - $errors[] = $element->outertext; - } - } - } - } - - // check styles. - if ( $content['css_parsed'] ) { - $errors = array_merge( ac_css_text_decoration_blink_check( $content ), $errors ); - } - - return $errors; -} - -/** - * CSS Text Decoration Blink Check - * - * @param obj $content object to check. - * @return array - */ -function ac_css_text_decoration_blink_check( $content ) { - - $dom = $content['html']; - $errors = []; - $error_code = ''; - $css_array = $content['css_parsed']; - - if ( $css_array ) { - foreach ( $css_array as $element => $rules ) { - if ( array_key_exists( 'text-decoration', $rules ) ) { - - // replace CSS variables. - $rules['text-decoration'] = edac_replace_css_variables( $rules['text-decoration'], $css_array ); - - if ( 'blink' === $rules['text-decoration'] || 'Blink' === $rules['text-decoration'] ) { - $error_code = $element . '{ '; - foreach ( $rules as $key => $value ) { - $error_code .= $key . ': ' . $value . '; '; - } - $error_code .= '}'; - - $elements = $dom->find( $element ); - if ( $elements ) { - foreach ( $elements as $element ) { - $errors[] = $element->outertext . ' ' . $error_code; - } - } - } - } - } - } - - return $errors; -} From 70141773ff78252aa49503b634b8085ff12f59a0 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 18:09:57 +0100 Subject: [PATCH 36/70] Add some inline comments to detail how combined rules are handled --- includes/classes/class-rest-api.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/includes/classes/class-rest-api.php b/includes/classes/class-rest-api.php index 5d54625b..d7e69f17 100644 --- a/includes/classes/class-rest-api.php +++ b/includes/classes/class-rest-api.php @@ -199,6 +199,7 @@ public function set_post_scan_results( $request ) { if ( array_key_exists( 'ruleset', $rule ) && 'js' === $rule['ruleset'] ) { $js_rule_ids[] = $rule['slug']; + // Some rules can be a grouping of other checks with different ids. This tracks those combined check IDs for later mapping. if ( array_key_exists( 'combines', $rule ) && ! empty( $rule['combines'] ) ) { foreach ( $rule['combines'] as $combine_rule_id ) { $combined_rule_ids[ $combine_rule_id ] = $rule['slug']; @@ -231,6 +232,7 @@ public function set_post_scan_results( $request ) { foreach ( $violations as $violation ) { $rule_id = $violation['ruleId']; + // If this rule is a combined rule then map it to the actual reporting rule ID. $actual_rule_id = array_key_exists( $rule_id, $combined_rule_ids ) ? $combined_rule_ids[ $rule_id ] : $rule_id; if ( in_array( $actual_rule_id, $js_rule_ids, true ) ) { From ce2a14f1c48dd614f0072e47de0423e047df4a7d Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 18:11:38 +0100 Subject: [PATCH 37/70] Remove some code added for testing --- includes/classes/class-rest-api.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/includes/classes/class-rest-api.php b/includes/classes/class-rest-api.php index d7e69f17..9b1668b4 100644 --- a/includes/classes/class-rest-api.php +++ b/includes/classes/class-rest-api.php @@ -306,10 +306,6 @@ public function set_post_scan_results( $request ) { // store a record of this scan in the post's meta. update_post_meta( $post_id, '_edac_post_checked_js', time() ); - if ( true === $request['isFailure'] ) { - update_post_meta( $post_id, '_edac_post_checked_js_failure', time() ); - } - return new \WP_REST_Response( [ 'success' => true, From c717a64e9960ccb53cd53fa5ac82354f5af9f6ba Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 19:28:33 +0100 Subject: [PATCH 38/70] Add missing trailing comma --- includes/rules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/rules.php b/includes/rules.php index 04779632..5a5289d8 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -427,5 +427,5 @@ 'rule_type' => 'error', 'summary' => esc_html__( 'Zooming is disabled via viewport meta tag that includes `user-scalable=no` or a `maximum-scale` value of less than 2. This limits low-vision users that want to increase text sizes, zoom into the page or who use a magnifier.', 'accessibility-checker' ), 'ruleset' => 'js', - ] + ], ]; From 17a07e3549e2fc28ec85ab7d729732084b161b94 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 19:33:18 +0100 Subject: [PATCH 39/70] Add back the meta-viewport rule after merged develop in --- src/pageScanner/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pageScanner/index.js b/src/pageScanner/index.js index 3f5ea1c1..fb8e9d22 100644 --- a/src/pageScanner/index.js +++ b/src/pageScanner/index.js @@ -56,6 +56,7 @@ const scan = async ( values: [ 'color_contrast_failure', 'underlined_text', + 'meta-viewport', ], }, From 5e43763aae6007697ccef70cf0006a6af860cf1c Mon Sep 17 00:00:00 2001 From: William Patton Date: Wed, 22 May 2024 19:49:42 +0100 Subject: [PATCH 40/70] Add a since tag to new method --- includes/classes/class-rest-api.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/classes/class-rest-api.php b/includes/classes/class-rest-api.php index e9bfe0a8..97f636f4 100644 --- a/includes/classes/class-rest-api.php +++ b/includes/classes/class-rest-api.php @@ -167,6 +167,7 @@ function () use ( $ns, $version ) { * * This can be used to store additional data in the html of the violation. * + * @since 1.13.0 * @param string $html The html of the violation. * @param string $rule_id The id of the rule. * @param array $violation The violation data. From e8a7b7667220f5fab59a02bbe0417ca796bd02a0 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 14:57:25 +0100 Subject: [PATCH 41/70] Re-add the filter on html to make elements unique when they typically won't be --- includes/classes/class-rest-api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/classes/class-rest-api.php b/includes/classes/class-rest-api.php index 8d7fe069..26d6829c 100644 --- a/includes/classes/class-rest-api.php +++ b/includes/classes/class-rest-api.php @@ -262,7 +262,7 @@ public function set_post_scan_results( $request ) { // This rule is one that we've included in our js ruleset. - $html = $violation['html']; + $html = apply_filters( 'edac_filter_js_violation_html', $violation['html'], $rule_id, $violation ); $impact = $violation['impact']; // by default, use the impact setting from the js rule. //phpcs:ignore Generic.Commenting.Todo.TaskFound From 1b380f2fd6a2469bb155d4eb6651172813dbe592 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 14:57:55 +0100 Subject: [PATCH 42/70] Pass and use the version string when including the pagescanner bundle in editorapp --- admin/class-enqueue-admin.php | 1 + src/editorApp/checkPage.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/admin/class-enqueue-admin.php b/admin/class-enqueue-admin.php index 0d908a90..387cbc83 100644 --- a/admin/class-enqueue-admin.php +++ b/admin/class-enqueue-admin.php @@ -122,6 +122,7 @@ public static function maybe_enqueue_admin_and_editor_app_scripts() { $post_id, [ 'edac_pageScanner' => 1 ] ), + 'version' => EDAC_VERSION, ] ); diff --git a/src/editorApp/checkPage.js b/src/editorApp/checkPage.js index 8c4c6406..33f54aa7 100644 --- a/src/editorApp/checkPage.js +++ b/src/editorApp/checkPage.js @@ -82,7 +82,7 @@ const injectIframe = ( previewUrl, postID ) => { // inject the scanner app. const scannerScriptElement = iframeDocument.createElement( 'script' ); // eslint-disable-next-line camelcase - scannerScriptElement.src = edac_editor_app.baseurl + '/build/pageScanner.bundle.js'; + scannerScriptElement.src = edac_editor_app.baseurl + '/build/pageScanner.bundle.js?v=' + edac_editor_app.version; iframeDocument.head.appendChild( scannerScriptElement ); } } ); From a98fbc0390106873331b31afe18493aaae69f8f9 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 16:17:24 +0100 Subject: [PATCH 43/70] Make meta-viewport a combines and rename the reported rule to meta_viewport This is for consistency with the other rules that all use underscores --- includes/rules.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/includes/rules.php b/includes/rules.php index 4c840eaa..4f1792b6 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -436,9 +436,10 @@ [ 'title' => esc_html__( 'Zooming and scaling is disabled', 'accessibility-checker' ), 'info_url' => 'https://a11ychecker.com/help###', - 'slug' => 'meta-viewport', + 'slug' => 'meta_viewport', 'rule_type' => 'error', 'summary' => esc_html__( 'Zooming is disabled via viewport meta tag that includes `user-scalable=no` or a `maximum-scale` value of less than 2. This limits low-vision users that want to increase text sizes, zoom into the page or who use a magnifier.', 'accessibility-checker' ), 'ruleset' => 'js', + 'combines' => [ 'meta-viewport' ], ], ]; From bfcdb70dbcc0ee903187dd350221a4c44654ce45 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 16:19:02 +0100 Subject: [PATCH 44/70] Lower threshold for flagging justified text to 200 characters --- src/pageScanner/rules/text-justified.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pageScanner/rules/text-justified.js b/src/pageScanner/rules/text-justified.js index 389b2ef0..3f8eb0ec 100644 --- a/src/pageScanner/rules/text-justified.js +++ b/src/pageScanner/rules/text-justified.js @@ -4,7 +4,7 @@ * Text elements should not be justified because it interferes with readability. */ -const TEXT_JUSTIFIED_CHECK_THRESHOLD = 500; +const TEXT_JUSTIFIED_CHECK_THRESHOLD = 200; export default { id: 'text_justified', selector: 'p, div, td', From 497d90d23cd9279a0a8a339a21ff54608060a6cb Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 16:26:25 +0100 Subject: [PATCH 45/70] Use a wider group of selectors for text_justified check --- src/pageScanner/rules/text-justified.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pageScanner/rules/text-justified.js b/src/pageScanner/rules/text-justified.js index 3f8eb0ec..904a6785 100644 --- a/src/pageScanner/rules/text-justified.js +++ b/src/pageScanner/rules/text-justified.js @@ -7,7 +7,7 @@ const TEXT_JUSTIFIED_CHECK_THRESHOLD = 200; export default { id: 'text_justified', - selector: 'p, div, td', + selector: 'p, span, small, strong, b, i, em, h1, h2, h3, h4, h5, h6, a, label, button, th, td, li, div, blockquote, address, cite, q, s, sub, sup, u, del, caption, dt, dd, figcaption, summary, data, time', matches: ( element ) => { return element.textContent.trim().length >= TEXT_JUSTIFIED_CHECK_THRESHOLD; }, From 680c8689087e754670e43ea2e6a1a1467ae8a468 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 19:55:48 +0100 Subject: [PATCH 46/70] Add some tags to the text_small rule --- src/pageScanner/rules/text-small.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pageScanner/rules/text-small.js b/src/pageScanner/rules/text-small.js index b88b7b55..e8d2c9b5 100644 --- a/src/pageScanner/rules/text-small.js +++ b/src/pageScanner/rules/text-small.js @@ -12,7 +12,7 @@ export default { // only run checks on elements with text content return element.textContent.trim().length; }, - tags: [ 'cat.text' ], + tags: [ 'wcag2aaa', 'wcag144', 'wcag148', 'cat.text' ], metadata: { description: 'Text elements should not be too small.', }, From 1fc87d214f94560592a44b1b777708bf8dea676b Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 19:56:25 +0100 Subject: [PATCH 47/70] Narrow the tags text_small checks against slightly --- src/pageScanner/rules/text-small.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pageScanner/rules/text-small.js b/src/pageScanner/rules/text-small.js index e8d2c9b5..7423a431 100644 --- a/src/pageScanner/rules/text-small.js +++ b/src/pageScanner/rules/text-small.js @@ -7,7 +7,7 @@ export default { id: 'text_small', impact: 'moderate', - selector: 'p, span, small, strong, b, i, h1, h2, h3, h4, h5, h6, a, label, button, th, td, li, div, blockquote, address, cite, code, pre, q, s, sub, sup, u, var, abbr, acronym, del, dfn, em, ins, kbd, samp, time, mark, meter, progress, ruby, rt, rp, wbr, bdi, bdo, br, hr, img, input, select, textarea, output, video, audio, canvas, map, area, object, embed, param, source, track, iframe, table, caption, col, colgroup, thead, tbody, tfoot, tr, th, td, dl, dt, dd, ol, ul, menu, dir, li, figure, figcaption, main, header, footer, nav, section, article, aside, details, dialog, summary, data, time, title, style, script, noscript, template', + selector: 'p, span, small, strong, b, i, h1, h2, h3, h4, h5, h6, a, label, button, th, td, li, div, blockquote, address, cite, code, pre, q, s, sub, sup, u, var, abbr, acronym, del, dfn, em, ins, kbd, input, select, textarea, caption, dl, dt, dd, li, figure, figcaption, details, dialog, summary, data, time', matches: ( element ) => { // only run checks on elements with text content return element.textContent.trim().length; From d895dfd256ddd70c8a71ce27821e3109e7bc6291 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 21:18:22 +0100 Subject: [PATCH 48/70] Don't pass on child nodes if the first node is a text node. --- src/pageScanner/checks/paragraph-not-empty.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pageScanner/checks/paragraph-not-empty.js b/src/pageScanner/checks/paragraph-not-empty.js index 6a7b965f..e170d205 100644 --- a/src/pageScanner/checks/paragraph-not-empty.js +++ b/src/pageScanner/checks/paragraph-not-empty.js @@ -12,12 +12,12 @@ export default { return true; } - // if there are child nodes then it passes. - if ( node.childNodes.length ) { + // Pass if there are child nodes and the first child is not a text node (notType of 3). + if ( node.childNodes.length && node.childNodes[ 0 ].nodeType !== 3 ) { return true; } - // if there is text content then it passes, false otherwise. + // If there is text content then it passes. return node.textContent.trim() !== ''; }, }; From 38ddafbdbbc1c8469bde57416eb604a7212aa73c Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 21:19:55 +0100 Subject: [PATCH 49/70] Add a temporary link that points to docs for empty paragraphs --- includes/rules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/rules.php b/includes/rules.php index de381dff..89830aeb 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -76,7 +76,7 @@ ], [ 'title' => esc_html__( 'Empty Paragraph Tag', 'accessibility-checker' ), - 'info_url' => 'https://a11ychecker.com/', + 'info_url' => 'https://equalizedigital.com/accessibility-checker/empty-paragraph-tag/', 'slug' => 'empty_paragraph_tag', 'rule_type' => 'warning', 'summary' => esc_html__( 'An Empty Paragraph Tag warning means there is a paragraph tag present that does not contain content. These may be announced by screen readers or create confusion for users. To fix this warning, remove the empty paragraphs from the page. If you need to add spacing between sections, this should be done with padding, margins, or a spacer block.', 'accessibility-checker' ), From 9c1ac6fa64f298b27b93fe2524f5ce260efc754c Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 22:13:15 +0100 Subject: [PATCH 50/70] Don't check possible headings if they are in blockquote, figcaption or table cell --- src/pageScanner/rules/possible-heading.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pageScanner/rules/possible-heading.js b/src/pageScanner/rules/possible-heading.js index 25cf8e09..1177953f 100644 --- a/src/pageScanner/rules/possible-heading.js +++ b/src/pageScanner/rules/possible-heading.js @@ -1,6 +1,10 @@ export default { id: 'possible_heading', selector: 'p', + matches: ( node ) => { + // not inside a blockquote, figcaption or table cell + return ! node.closest( 'blockquote, figcaption, td' ); + }, excludeHidden: false, tags: [ 'cat.text', From 094397d2d75d62a7535945b543c220558e57a000 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Thu, 23 May 2024 16:17:24 +0100 Subject: [PATCH 51/70] Make meta-viewport a combines and rename the reported rule to meta_viewport This is for consistency with the other rules that all use underscores --- includes/rules.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/includes/rules.php b/includes/rules.php index 5a5289d8..3499df05 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -423,9 +423,10 @@ [ 'title' => esc_html__( 'Zooming and scaling is disabled', 'accessibility-checker' ), 'info_url' => 'https://a11ychecker.com/help###', - 'slug' => 'meta-viewport', + 'slug' => 'meta_viewport', 'rule_type' => 'error', 'summary' => esc_html__( 'Zooming is disabled via viewport meta tag that includes `user-scalable=no` or a `maximum-scale` value of less than 2. This limits low-vision users that want to increase text sizes, zoom into the page or who use a magnifier.', 'accessibility-checker' ), 'ruleset' => 'js', + 'combines' => [ 'meta-viewport' ], ], ]; From ec78362f8b33ef261597c07c3006d02770b81c63 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 22 May 2024 18:02:58 +0100 Subject: [PATCH 52/70] Add some handling for reported rules that are 'combined' from other checks in JS --- includes/classes/class-rest-api.php | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/includes/classes/class-rest-api.php b/includes/classes/class-rest-api.php index e1a93e03..5d54625b 100644 --- a/includes/classes/class-rest-api.php +++ b/includes/classes/class-rest-api.php @@ -161,8 +161,6 @@ function () use ( $ns, $version ) { ); } - - /** * REST handler that saves to the DB a list of js rule violations for a post. * @@ -194,11 +192,18 @@ public function set_post_scan_results( $request ) { //phpcs:ignore Generic.Commenting.Todo.TaskFound // TODO: setup a rules class for loading/filtering rules. - $rules = edac_register_rules(); - $js_rule_ids = []; + $rules = edac_register_rules(); + $js_rule_ids = []; + $combined_rule_ids = []; foreach ( $rules as $rule ) { if ( array_key_exists( 'ruleset', $rule ) && 'js' === $rule['ruleset'] ) { $js_rule_ids[] = $rule['slug']; + + if ( array_key_exists( 'combines', $rule ) && ! empty( $rule['combines'] ) ) { + foreach ( $rule['combines'] as $combine_rule_id ) { + $combined_rule_ids[ $combine_rule_id ] = $rule['slug']; + } + } } } @@ -226,7 +231,9 @@ public function set_post_scan_results( $request ) { foreach ( $violations as $violation ) { $rule_id = $violation['ruleId']; - if ( in_array( $rule_id, $js_rule_ids, true ) ) { + $actual_rule_id = array_key_exists( $rule_id, $combined_rule_ids ) ? $combined_rule_ids[ $rule_id ] : $rule_id; + + if ( in_array( $actual_rule_id, $js_rule_ids, true ) ) { // This rule is one that we've included in our js ruleset. @@ -236,7 +243,7 @@ public function set_post_scan_results( $request ) { //phpcs:ignore Generic.Commenting.Todo.TaskFound // TODO: setup a rules class for loading/filtering rules. foreach ( $rules as $rule ) { - if ( $rule['slug'] === $rule_id ) { + if ( $rule['slug'] === $actual_rule_id ) { $impact = $rule['rule_type']; // if we are defining the rule_type in php rules config, use that instead of the js rule's impact setting. } } @@ -255,9 +262,9 @@ public function set_post_scan_results( $request ) { * @param string $rule_id The rule ID. * @param string $type The type of validation which is always 'js' in this path. */ - do_action( 'edac_before_rule', $post_id, $rule_id, 'js' ); + do_action( 'edac_before_rule', $post_id, $actual_rule_id, 'js' ); - ( new Insert_Rule_Data() )->insert( $post, $rule_id, $impact, $html ); + ( new Insert_Rule_Data() )->insert( $post, $actual_rule_id, $impact, $html ); /** * Fires after a rule is run against the content. @@ -270,7 +277,7 @@ public function set_post_scan_results( $request ) { * @param string $rule_id The rule ID. * @param string $type The type of validation which is always 'js' in this path. */ - do_action( 'edac_after_rule', $post_id, $rule_id, 'js' ); + do_action( 'edac_after_rule', $post_id, $actual_rule_id, 'js' ); } } @@ -297,6 +304,10 @@ public function set_post_scan_results( $request ) { // store a record of this scan in the post's meta. update_post_meta( $post_id, '_edac_post_checked_js', time() ); + if ( true === $request['isFailure'] ) { + update_post_meta( $post_id, '_edac_post_checked_js_failure', time() ); + } + return new \WP_REST_Response( [ 'success' => true, From dca64deb74328f5888bf0d3e12f04f57f964bb8a Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 24 May 2024 14:46:36 +0100 Subject: [PATCH 53/70] Update text_justified summary text --- includes/rules.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/includes/rules.php b/includes/rules.php index 9b8151f1..b4a549dc 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -104,13 +104,7 @@ 'info_url' => 'https://a11ychecker.com/help1980', 'slug' => 'text_justified', 'rule_type' => 'warning', - 'summary' => sprintf( - // translators: %s is <p>, %s is <div>, %s is <td>. - esc_html__( 'A Text Justified warning shows up in Accessibility Checker when the text on your post or page, either a %1$s, %2$s, or %3$s element, with more than 500 characters has been styled with a justified alignment (text-align:justify). To fix this warning, you will need to remove the justified styling from the specified text elements.', 'accessibility-checker' ), - '<p>', - '<div>', - '<td>' - ), + 'summary' => esc_html__( 'A Text Justified warning appears in Accessibility Checker when text with more than 200 characters on your post or page is styled with justified alignment (text-align:justify). To fix this warning, remove the justified styling from the specified text elements.', 'accessibility-checker' ), 'ruleset' => 'js', ], [ From fc2f32540cdddbd4c9bbef3a36622a3731a73092 Mon Sep 17 00:00:00 2001 From: William Patton Date: Fri, 24 May 2024 15:04:38 +0100 Subject: [PATCH 54/70] Update info/docs link for empty paragraph rule --- includes/rules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/rules.php b/includes/rules.php index 89830aeb..5b6d47d8 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -76,7 +76,7 @@ ], [ 'title' => esc_html__( 'Empty Paragraph Tag', 'accessibility-checker' ), - 'info_url' => 'https://equalizedigital.com/accessibility-checker/empty-paragraph-tag/', + 'info_url' => 'https://a11ychecker.com/help7870', 'slug' => 'empty_paragraph_tag', 'rule_type' => 'warning', 'summary' => esc_html__( 'An Empty Paragraph Tag warning means there is a paragraph tag present that does not contain content. These may be announced by screen readers or create confusion for users. To fix this warning, remove the empty paragraphs from the page. If you need to add spacing between sections, this should be done with padding, margins, or a spacer block.', 'accessibility-checker' ), From 404bc157bcd9258f1aa86b39b416463aeda0d5eb Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 24 May 2024 15:06:02 +0100 Subject: [PATCH 55/70] Add text for possible_heading rule --- src/pageScanner/rules/possible-heading.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pageScanner/rules/possible-heading.js b/src/pageScanner/rules/possible-heading.js index 1177953f..70635470 100644 --- a/src/pageScanner/rules/possible-heading.js +++ b/src/pageScanner/rules/possible-heading.js @@ -7,7 +7,10 @@ export default { }, excludeHidden: false, tags: [ - 'cat.text', + 'wcag2a', + 'wcag131', + 'wcag241', + 'cat.semantics', ], metadata: { description: 'Headings should be used to convey the structure of the page, not styled paragraphs', From 01b14e675d4af5817f412b775ded50fef5053390 Mon Sep 17 00:00:00 2001 From: Steve Jones Date: Fri, 24 May 2024 10:07:21 -0400 Subject: [PATCH 56/70] added - viewable option to rules array and updated conditional on the details panel --- admin/class-ajax.php | 2 +- includes/rules.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/admin/class-ajax.php b/admin/class-ajax.php index 1fff9869..8d3928df 100644 --- a/admin/class-ajax.php +++ b/admin/class-ajax.php @@ -415,7 +415,7 @@ function ( $a, $b ) { $html .= ''; - if ( 'missing_headings' !== $rule['slug'] ) { + if ( ! isset( $rule['viewable'] ) || $rule['viewable'] ) { $url = add_query_arg( [ diff --git a/includes/rules.php b/includes/rules.php index 3499df05..0713b066 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -98,6 +98,7 @@ '<h1>', '<h6>' ), + 'viewable' => false, ], [ 'title' => esc_html__( 'Text Justified', 'accessibility-checker' ), @@ -428,5 +429,6 @@ 'summary' => esc_html__( 'Zooming is disabled via viewport meta tag that includes `user-scalable=no` or a `maximum-scale` value of less than 2. This limits low-vision users that want to increase text sizes, zoom into the page or who use a magnifier.', 'accessibility-checker' ), 'ruleset' => 'js', 'combines' => [ 'meta-viewport' ], + 'viewable' => false, ], ]; From cddf1ae2bcf3bc0d42aae87e276e45eb3b6edf3a Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 24 May 2024 15:09:37 +0100 Subject: [PATCH 57/70] Update some code comments --- src/pageScanner/checks/paragraph-styled-as-header.js | 6 +++--- src/pageScanner/rules/possible-heading.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pageScanner/checks/paragraph-styled-as-header.js b/src/pageScanner/checks/paragraph-styled-as-header.js index c299cb15..f7187d91 100644 --- a/src/pageScanner/checks/paragraph-styled-as-header.js +++ b/src/pageScanner/checks/paragraph-styled-as-header.js @@ -22,12 +22,12 @@ export default { evaluate: ( node ) => { const pixelSize = fontSizeInPx( node ); - // long paragraphs or with size under 16px are unlikely to be headers. + // Long paragraphs or those with font size under 16px are unlikely to be headers. if ( node.textContent.trim().length > 50 || pixelSize < 16 ) { return false; } - // paragraphs that are 20px or more are probably headers. + // Paragraphs that are 20px or more are probably headers. if ( pixelSize >= 20 ) { return true; } @@ -46,7 +46,7 @@ export default { return true; } - // didn't find anything indicating this is a possible header. + // Didn't find anything indicating this is a possible header. return false; }, }; diff --git a/src/pageScanner/rules/possible-heading.js b/src/pageScanner/rules/possible-heading.js index 70635470..9c1f5043 100644 --- a/src/pageScanner/rules/possible-heading.js +++ b/src/pageScanner/rules/possible-heading.js @@ -2,7 +2,7 @@ export default { id: 'possible_heading', selector: 'p', matches: ( node ) => { - // not inside a blockquote, figcaption or table cell + // Not inside a blockquote, figcaption or table cell return ! node.closest( 'blockquote, figcaption, td' ); }, excludeHidden: false, From 26c5f541554d9c6a95cd3ffd8dd2d778fb829a8e Mon Sep 17 00:00:00 2001 From: William Patton Date: Fri, 24 May 2024 15:18:03 +0100 Subject: [PATCH 58/70] Simplify the node value check early bail Co-authored-by: Steve Jones --- src/pageScanner/helpers/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pageScanner/helpers/helpers.js b/src/pageScanner/helpers/helpers.js index 7c16e66f..620bcc3c 100644 --- a/src/pageScanner/helpers/helpers.js +++ b/src/pageScanner/helpers/helpers.js @@ -1,5 +1,5 @@ export const fontSizeInPx = ( node ) => { - if ( node === null || node === 'undefined' || node.nodeType !== Node.ELEMENT_NODE ) { +if ( ! node || node.nodeType !== Node.ELEMENT_NODE ) { return 0; } From 6274a5b3732bcb5edaf8238b6ced7f5b8ba6343a Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 24 May 2024 19:51:16 +0100 Subject: [PATCH 59/70] Use a simplified catch for null and undefined as early bail --- src/pageScanner/helpers/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pageScanner/helpers/helpers.js b/src/pageScanner/helpers/helpers.js index 7c16e66f..bc779e3a 100644 --- a/src/pageScanner/helpers/helpers.js +++ b/src/pageScanner/helpers/helpers.js @@ -1,5 +1,5 @@ export const fontSizeInPx = ( node ) => { - if ( node === null || node === 'undefined' || node.nodeType !== Node.ELEMENT_NODE ) { + if ( ! node || node.nodeType !== Node.ELEMENT_NODE ) { return 0; } From 913aeca064676b9a9a326a5455677d9a96694ad5 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 24 May 2024 19:51:45 +0100 Subject: [PATCH 60/70] Handle potential `NaN` values by checking for instance of Number --- src/pageScanner/helpers/helpers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pageScanner/helpers/helpers.js b/src/pageScanner/helpers/helpers.js index bc779e3a..fa29db7b 100644 --- a/src/pageScanner/helpers/helpers.js +++ b/src/pageScanner/helpers/helpers.js @@ -3,5 +3,6 @@ export const fontSizeInPx = ( node ) => { return 0; } - return parseFloat( window.getComputedStyle( node ).fontSize ); + const fontSize = parseFloat( window.getComputedStyle( node ).fontSize ); + return fontSize instanceof Number ? fontSize : 0; }; From 7f9c3b88024facfec097c477b1734101f28bc859 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 24 May 2024 20:02:26 +0100 Subject: [PATCH 61/70] Fix extra space before opening bracket --- src/pageScanner/helpers/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pageScanner/helpers/helpers.js b/src/pageScanner/helpers/helpers.js index b12b6794..fa29db7b 100644 --- a/src/pageScanner/helpers/helpers.js +++ b/src/pageScanner/helpers/helpers.js @@ -1,5 +1,5 @@ export const fontSizeInPx = ( node ) => { - if ( ! node || node.nodeType !== Node.ELEMENT_NODE ) { + if ( ! node || node.nodeType !== Node.ELEMENT_NODE ) { return 0; } From 6322ea8ef1f97e683ece7712af4c1896de00b1d0 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 24 May 2024 21:16:41 +0100 Subject: [PATCH 62/70] Don't flag missing iframe title if it's display: none and visibility: hidden Google tag manager iframe should no longer create noise with this change --- includes/rules/iframe_missing_title.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/includes/rules/iframe_missing_title.php b/includes/rules/iframe_missing_title.php index 545fe0ad..ed1bbdb4 100644 --- a/includes/rules/iframe_missing_title.php +++ b/includes/rules/iframe_missing_title.php @@ -1,6 +1,6 @@ getAttribute( 'title' ) ) && empty( $iframe->getAttribute( 'aria-label' ) ) ) { + $display_none_and_visibility_hidden = preg_match( '/(?=.*display\s*:\s*none)(?=.*visibility\s*:\s*hidden)/is', $iframe->getAttribute( 'style' ) ); + if ( $display_none_and_visibility_hidden ) { + continue; + } + $iframecode = htmlspecialchars( $iframe->outertext ); $errors[] = $iframecode; From 7f9657305da38ec3910717d2265c1e1ac4596dd3 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Fri, 24 May 2024 21:27:24 +0100 Subject: [PATCH 63/70] Check for `typeof` 'number' instead of `instanceof Number` --- src/pageScanner/helpers/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pageScanner/helpers/helpers.js b/src/pageScanner/helpers/helpers.js index fa29db7b..6c004fce 100644 --- a/src/pageScanner/helpers/helpers.js +++ b/src/pageScanner/helpers/helpers.js @@ -4,5 +4,5 @@ export const fontSizeInPx = ( node ) => { } const fontSize = parseFloat( window.getComputedStyle( node ).fontSize ); - return fontSize instanceof Number ? fontSize : 0; + return typeof fontSize === 'number' ? fontSize : 0; }; From 47bb153d6404451c1a2ce938fc6f01b9746cc71f Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 28 May 2024 14:13:56 +0100 Subject: [PATCH 64/70] Update the zooming and scaling user facing title and the help link --- includes/rules.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/rules.php b/includes/rules.php index c1007f9e..2b1bccf0 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -429,8 +429,8 @@ ), ], [ - 'title' => esc_html__( 'Zooming and scaling is disabled', 'accessibility-checker' ), - 'info_url' => 'https://a11ychecker.com/help###', + 'title' => esc_html__( 'Zooming and Scaling Disabled', 'accessibility-checker' ), + 'info_url' => 'https://a11ychecker.com/help7947', 'slug' => 'meta_viewport', 'rule_type' => 'error', 'summary' => esc_html__( 'Zooming is disabled via viewport meta tag that includes `user-scalable=no` or a `maximum-scale` value of less than 2. This limits low-vision users that want to increase text sizes, zoom into the page or who use a magnifier.', 'accessibility-checker' ), From 99ebe931b9b617fc20f434afe3add814d3f138ea Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 28 May 2024 14:23:31 +0100 Subject: [PATCH 65/70] Remove the dry run flag in the deploy-on-release-to-dot-org.yml workflow --- .github/workflows/deploy-on-release-to-dot-org.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/deploy-on-release-to-dot-org.yml b/.github/workflows/deploy-on-release-to-dot-org.yml index 5f2f941d..8865b217 100644 --- a/.github/workflows/deploy-on-release-to-dot-org.yml +++ b/.github/workflows/deploy-on-release-to-dot-org.yml @@ -39,8 +39,6 @@ jobs: - name: WordPress plugin deploy id: deploy uses: 10up/action-wordpress-plugin-deploy@stable - with: - dry-run: true # exists to prevent accidental deploys during testing env: SVN_USERNAME: ${{ secrets.SVN_USERNAME }} SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} From 5c09e0063d4e72675fd7f7f18dedc95e581b4995 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 28 May 2024 15:00:33 +0100 Subject: [PATCH 66/70] Bump version 1.12.0 -> 1.13.0 --- accessibility-checker.php | 4 ++-- package.json | 2 +- readme.txt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/accessibility-checker.php b/accessibility-checker.php index 8a6de117..6f0cc531 100755 --- a/accessibility-checker.php +++ b/accessibility-checker.php @@ -10,7 +10,7 @@ * Plugin Name: Accessibility Checker * Plugin URI: https://a11ychecker.com * Description: Audit and check your website for accessibility before you hit publish. In-post accessibility scanner and guidance. - * Version: 1.12.0 + * Version: 1.13.0 * Author: Equalize Digital * Author URI: https://equalizedigital.com * License: GPL-2.0+ @@ -35,7 +35,7 @@ // Current plugin version. if ( ! defined( 'EDAC_VERSION' ) ) { - define( 'EDAC_VERSION', '1.12.0' ); + define( 'EDAC_VERSION', '1.13.0' ); } // Current database version. diff --git a/package.json b/package.json index 5e1bee1f..effdd0ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "accessibility-checker", - "version": "1.12.0", + "version": "1.13.0", "description": "Audit and check your website for accessibility before you hit publish. In-post accessibility scanner and guidance.", "author": "Equalize Digital", "license": "GPL-2.0+", diff --git a/readme.txt b/readme.txt index 46147899..6558603d 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: equalizedigital, alh0319, stevejonesdev Tags: accessibility, accessible, wcag, ada, WP accessibility Requires at least: 6.2 Tested up to: 6.5.3 -Stable tag: 1.12.0 +Stable tag: 1.13.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html From 4c0f166d487e814797b5e4e09612e4f7633d7f9a Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 28 May 2024 15:18:28 +0100 Subject: [PATCH 67/70] Add changelog for 1.13.0 --- readme.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/readme.txt b/readme.txt index 6558603d..b679385d 100644 --- a/readme.txt +++ b/readme.txt @@ -171,6 +171,17 @@ No, Accessibility Checker runs completely on your server and does not require yo == Changelog == += 1.13.0 = +* Added: Meta Viewport zoom-able and scale-able check +* Added: Empty Paragraph warning +* Fixed: Properly determine possible headings with computed styles +* Improved: Better detection of the underlined text +* Improved: Better detection of small text +* Improved: Better detection of justified text +* Improved: Better detection of blink and marquee tags +* Improved: No longer flagging GTM iframes as missing title since they are display: none and visibility: hidden +* Enhancement: Do not show 'View on page' link to frontend when the issues cannot be viewed + = 1.12.0 = * Fixed: Use the last generation time in summary widgets rather than last completed scan time * Improved: More accessible panels in the editor From 39e9fc0c09e3721019dadc1f6cf0d05c94b9eb75 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 28 May 2024 19:27:03 +0100 Subject: [PATCH 68/70] Correct missing summaries in some rules --- includes/rules.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/includes/rules.php b/includes/rules.php index 2b1bccf0..98ff865b 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -41,7 +41,11 @@ 'info_url' => 'https://a11ychecker.com/help1930', 'slug' => 'img_linked_alt_missing', 'rule_type' => 'error', - 'summary' => esc_html__( 'A Low-quality Alternative Text warning appears when the alternative text on an image contains keywords that are unnecessary in alternative text (such as "image" or "graphic"), a file extension (such as .JPG), that may be describing a decorative image (such as "spacer" or "arrow"). To fix this warning, you will need to rewrite the alternative text for any images that flagged the Low-Quality Alternative Text warning, ensuring the alternative text is accurate, unique, contextually appropriate, and does not contain redundant or unnecessary descriptors. If the image is purely decorative, it is correct to leave the alternative text blank.', 'accessibility-checker' ), + 'summary' => sprintf( + // translators: %s is alt="". + esc_html__( 'A Linked Image Missing Alternative Text error appears when an image that is linked to a URL does not have an alt attribute (%s) in the image tag at all. Linked images must have accurate alternative text that describes where the link goes so that screen reader users know where the link is pointing. To resolve this error you need to add meaningful alt text to the image. Your alt text should describe the link purpose not what the image looks like.', 'accessibility-checker' ), + 'alt=""' + ), ], [ 'title' => esc_html__( 'Linked Image Empty Alternative Text', 'accessibility-checker' ), @@ -59,7 +63,7 @@ 'info_url' => 'https://a11ychecker.com/help1976', 'slug' => 'img_alt_redundant', 'rule_type' => 'warning', - 'summary' => '', + 'summary' => esc_html__( 'Duplicate Alternative Text warnings appear when the alternative text for an image on your post or page is identical to nearby or adjacent text, including the image’s title or caption. This warning also occurs if two images on the page have the same alternative text. To resolve this warning, you will need to change the text of either one or both elements that flagged the Duplicate Alternative Text warning, ensuring that all images have unique alt text and that you are not repeating your alt text in your image titles and captions.', 'accessibility-checker' ), ], [ 'title' => esc_html__( 'Incorrect Heading Order', 'accessibility-checker' ), From 7f1392d20b6b5d03a330b895c68412d3e0b44a95 Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Tue, 28 May 2024 19:29:51 +0100 Subject: [PATCH 69/70] Fix some typos in summaries --- includes/rules.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/includes/rules.php b/includes/rules.php index 98ff865b..ce6e2543 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -53,7 +53,7 @@ 'slug' => 'img_linked_alt_empty', 'rule_type' => 'error', 'summary' => sprintf( - // translators: %s is alt="". + // translators: %s is alt="". esc_html__( 'A Linked Image Empty Alternative Text error appears when an image that is linked to a URL has an alt attribute (%s) with nothing in it. Linked images must have accurate alternative text that describes where the link goes so that screen reader users know where the link is pointing. To resolve this error you need to add meaningful alt text to the image. Your alt text should describe the link purpose not what the image looks like.', 'accessibility-checker' ), 'alt=""' ), @@ -266,7 +266,7 @@ 'rule_type' => 'error', 'summary' => sprintf( // translators: %1$s is <input>, %2$s is <label>, %3$s is for="". - esc_html__( 'A Missing Form Label error is triggered when an %1$s (form field) is present in your form and but is not associated with a %2$s element. This could mean the label is present but is missing a %3$s attribute to connect it to the applicable field or there could be no label present at all and only an %1$s tag. To fix missing form label errors, you will need to determine how the field and form were created and then add field labels or a correct %3$s attribute to exisiting labels that are not connected to a field.', 'accessibility-checker' ), + esc_html__( 'A Missing Form Label error is triggered when an %1$s (form field) is present in your form and but is not associated with a %2$s element. This could mean the label is present but is missing a %3$s attribute to connect it to the applicable field or there could be no label present at all and only an %1$s tag. To fix missing form label errors, you will need to determine how the field and form were created and then add field labels or a correct %3$s attribute to existing labels that are not connected to a field.', 'accessibility-checker' ), '<input>', '<label>', 'for=""' @@ -286,7 +286,7 @@ 'rule_type' => 'warning', 'summary' => sprintf( // translators: %s is <u>. - esc_html__( 'An Underlined Text warning appears if any text on your page is wrapped in an HTML underline tag (%1$s). In an online environment, underlined text is generally used to indicate linked text and it is not considerd a best practice to underline text for emphasis only. To fix underlined text, you will need to remove the %1$s element from the text or CSS styles that are making it underlined. Try using other stylization, such as italics, colored text, or bolding to emphasize or differentiate between words or phrases.', 'accessibility-checker' ), + esc_html__( 'An Underlined Text warning appears if any text on your page is wrapped in an HTML underline tag (%1$s). In an online environment, underlined text is generally used to indicate linked text and it is not considered a best practice to underline text for emphasis only. To fix underlined text, you will need to remove the %1$s element from the text or CSS styles that are making it underlined. Try using other stylization, such as italics, colored text, or bolding to emphasize or differentiate between words or phrases.', 'accessibility-checker' ), '<u>' ), 'ruleset' => 'js', @@ -377,7 +377,7 @@ 'rule_type' => 'error', 'summary' => sprintf( // translators: %1$s is <html>, %2$s is lang="", %3$s is xml:lang="". - esc_html__( 'A language declaration is an HTML attribute that denotes the default language of the content on a page or post. Language declarations should be coded into your website theme and appear automatically in the head of the website. A Missing Lanaguage Declaration error appears if the %1$s tag on the page does not contain a %2$s or %3$s attribute, or one of these attributes is present but is empty. To fix a Missing Language Declaration error, you will need to edit your theme files to add the missing language attribute to the HTML tag at the very top of your website header. If you are using a theme that receives updates, then you will need to make the change in a child theme to ensure the fix does not get overwritten when you next update your theme.', 'accessibility-checker' ), + esc_html__( 'A language declaration is an HTML attribute that denotes the default language of the content on a page or post. Language declarations should be coded into your website theme and appear automatically in the head of the website. A Missing Language Declaration error appears if the %1$s tag on the page does not contain a %2$s or %3$s attribute, or one of these attributes is present but is empty. To fix a Missing Language Declaration error, you will need to edit your theme files to add the missing language attribute to the HTML tag at the very top of your website header. If you are using a theme that receives updates, then you will need to make the change in a child theme to ensure the fix does not get overwritten when you next update your theme.', 'accessibility-checker' ), '<html>', 'lang', 'xml:lang' @@ -395,14 +395,14 @@ 'info_url' => 'https://a11ychecker.com/help4414', 'slug' => 'video_present', 'rule_type' => 'warning', - 'summary' => esc_html__( 'Because videos frequently contain accessibility problems, many of which can only be identified by a person, The A Video is Present warning appears anytime a video is detected on a post or page as a reminder that you need to manually test your video for accessibilty. To resolve this warning, you need to visit the front end of your website and confirm that the video in the warning is accessible. Once you have fully tested the video for accessibility, you need to fix any errors that may be present and then can “Ignore” the warning to mark it as complete.', 'accessibility-checker' ), + 'summary' => esc_html__( 'Because videos frequently contain accessibility problems, many of which can only be identified by a person, The A Video is Present warning appears anytime a video is detected on a post or page as a reminder that you need to manually test your video for accessibility. To resolve this warning, you need to visit the front end of your website and confirm that the video in the warning is accessible. Once you have fully tested the video for accessibility, you need to fix any errors that may be present and then can “Ignore” the warning to mark it as complete.', 'accessibility-checker' ), ], [ 'title' => esc_html__( 'A Slider is Present', 'accessibility-checker' ), 'info_url' => 'https://a11ychecker.com/help3264', 'slug' => 'slider_present', 'rule_type' => 'warning', - 'summary' => esc_html__( 'Because sliders frequently contain accessibility problems, many of which can only be identified by a person, the A Slider is Present warning appears anytime a slider is detected on a post or page as a reminder that you need to manually test your slider for accessibilty. To resolve this warning, you need to visit the front end of your website and confirm all sliders on the page are accessible. Once you have fully tested your sliders for accessibility, you need to fix any errors that may be present and then can “Ignore” the warning to mark it as complete.', 'accessibility-checker' ), + 'summary' => esc_html__( 'Because sliders frequently contain accessibility problems, many of which can only be identified by a person, the A Slider is Present warning appears anytime a slider is detected on a post or page as a reminder that you need to manually test your slider for accessibility. To resolve this warning, you need to visit the front end of your website and confirm all sliders on the page are accessible. Once you have fully tested your sliders for accessibility, you need to fix any errors that may be present and then can “Ignore” the warning to mark it as complete.', 'accessibility-checker' ), ], [ 'title' => esc_html__( 'Missing Title', 'accessibility-checker' ), From 4215ac5d479d10a3cc17c42b4fcb57b1123d92fc Mon Sep 17 00:00:00 2001 From: pattonwebz Date: Wed, 29 May 2024 14:08:00 +0100 Subject: [PATCH 70/70] Correct iframe_missing_title summary --- includes/rules.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/includes/rules.php b/includes/rules.php index ce6e2543..dd8bc796 100644 --- a/includes/rules.php +++ b/includes/rules.php @@ -92,11 +92,9 @@ 'slug' => 'iframe_missing_title', 'rule_type' => 'error', 'summary' => sprintf( - // translators: %1$s is <h3>, %2$s is <h1>, %3$s is <h2>. - esc_html__( 'An Incorrect Heading Order error means your heading structure has skipped over a level. For example, if your page structure has a level 3 heading (%1$s) under a level 1 heading (%2$s), an Incorrect Heading Order error will be flagged because there is no %3$s tag between the H1 and H2. To fix incorrect heading order errors, you will need to either change the incorrect heading level to the correct heading level, or add content with the correct heading level in between the two already existing levels.', 'accessibility-checker' ), - '<h3>', - '<h1>', - '<h2>' + // translators: %1$s is <frame>. + esc_html__( 'An iFrame Missing title error means that one or more of the iFrames on your post or page does not have an accessible title describing the contents of the iFrame. An iFrame title is an attribute that can be added to the %1$s tag to describe the contents of the frame to people using assistive technology. To fix a missing iFrame title, you will need to add a title or an aria-label attribute to the %1$s tag. The attribute should accurately describe the contents of the iFrame.', 'accessibility-checker' ), + '<iframe>', ), ], [