{ impact, wcag, title, help }. */ public static function all() { return array( 'html-lang' => array( 'error', '3.1.1', __( 'Page language is not set', 'accesswell' ), __( 'Screen readers need the lang attribute on the html element to pronounce the page correctly. Set the site language under Settings > General, and make sure the theme prints language_attributes() in its html tag.', 'accesswell' ) ), 'page-title' => array( 'error', '2.4.2', __( 'Page has no title', 'accesswell' ), __( 'The title is the first thing a screen reader announces. Give the page a title, and check that the theme supports the title-tag feature.', 'accesswell' ) ), 'viewport-zoom' => array( 'error', '1.4.4', __( 'Zooming is blocked', 'accesswell' ), __( 'The viewport meta tag stops people from zooming in (user-scalable=no, or a maximum scale below 2). Remove those values so text can be enlarged.', 'accesswell' ) ), 'landmark-main' => array( 'warning', '1.3.1', __( 'No main content landmark', 'accesswell' ), __( 'Wrap the main content in a main element so keyboard and screen reader users can jump straight to it. This is usually a change in the theme templates.', 'accesswell' ) ), 'skip-link' => array( 'notice', '2.4.1', __( 'No "skip to content" link', 'accesswell' ), __( 'A link at the very start of the page that jumps to the main content saves keyboard users from going through the whole menu on every page.', 'accesswell' ) ), 'heading-h1' => array( 'warning', '1.3.1', __( 'Page has no main heading (h1)', 'accesswell' ), __( 'Each page should have one h1 that says what the page is about, usually its title.', 'accesswell' ) ), 'heading-empty' => array( 'error', '2.4.6', __( 'Empty heading', 'accesswell' ), __( 'A heading with no text is announced as "heading" with nothing after it. Add text or remove the heading.', 'accesswell' ) ), 'heading-skip' => array( 'warning', '1.3.1', __( 'Heading level skipped', 'accesswell' ), __( 'Headings should go down one level at a time (h2, then h3) so the structure makes sense to screen reader users. Change the heading level, and use the block\'s typography settings to change its size instead.', 'accesswell' ) ), 'img-alt' => array( 'error', '1.1.1', __( 'Image has no alt attribute', 'accesswell' ), __( 'Describe what the image shows or does in its alternative text. If it is only decoration, leave the alternative text empty so screen readers skip it.', 'accesswell' ) ), 'img-alt-filename' => array( 'warning', '1.1.1', __( 'Alt text looks like a file name', 'accesswell' ), __( 'Alternative text such as "IMG_2041.jpg" or "image" says nothing about the picture. Describe what it shows instead.', 'accesswell' ) ), 'link-name' => array( 'error', '2.4.4', __( 'Link has no text', 'accesswell' ), __( 'This link has nothing a screen reader can announce: no text, no image alternative text and no label. Add link text, or alternative text to the linked image.', 'accesswell' ) ), 'link-vague' => array( 'warning', '2.4.4', __( 'Link text does not say where it goes', 'accesswell' ), __( 'Links like "click here" or "read more" make no sense when screen reader users list all links on a page. Use text that names the destination, such as "Read our opening hours".', 'accesswell' ) ), 'button-name' => array( 'error', '4.1.2', __( 'Button has no text', 'accesswell' ), __( 'Give the button visible text, or an aria-label when it only shows an icon.', 'accesswell' ) ), 'form-label' => array( 'error', '1.3.1', __( 'Form field has no label', 'accesswell' ), __( 'Every field needs a label that stays visible. Placeholder text is not a label: it disappears while typing and is often not read out.', 'accesswell' ) ), 'contrast' => array( 'error', '1.4.3', __( 'Text contrast is too low', 'accesswell' ), __( 'Text needs a contrast ratio of at least 4.5:1 against its background, or 3:1 for large text. Darken the text or lighten the background.', 'accesswell' ) ), 'contrast-image' => array( 'notice', '1.4.3', __( 'Text over an image: check contrast', 'accesswell' ), __( 'This text sits on a background image or gradient, so its contrast cannot be measured. Check that it is easy to read everywhere, or add a solid or darkened overlay.', 'accesswell' ) ), 'table-headers' => array( 'warning', '1.3.1', __( 'Table has no header cells', 'accesswell' ), __( 'Data tables need header cells (th) so each value is read with its column or row name. In the Table block, turn on "Header section".', 'accesswell' ) ), 'list-structure' => array( 'error', '1.3.1', __( 'List item outside a list', 'accesswell' ), __( 'A list item must be inside a ul or ol element, or it is not announced as part of a list.', 'accesswell' ) ), 'iframe-title' => array( 'error', '4.1.2', __( 'Embedded frame has no title', 'accesswell' ), __( 'Give the iframe a title attribute that says what it contains, such as "Map of our office".', 'accesswell' ) ), 'media-autoplay' => array( 'warning', '1.4.2', __( 'Media plays sound automatically', 'accesswell' ), __( 'Audio or video that plays with sound on its own talks over screen readers. Turn off autoplay, or mute it.', 'accesswell' ) ), 'aria-hidden-focus' => array( 'error', '4.1.2', __( 'Hidden from screen readers but still focusable', 'accesswell' ), __( 'Something inside aria-hidden="true" can still receive keyboard focus, so keyboard users land on an element screen readers say nothing about. Remove aria-hidden, or take the element out of the tab order.', 'accesswell' ) ), 'tabindex-positive' => array( 'warning', '2.4.3', __( 'Positive tabindex', 'accesswell' ), __( 'A tabindex above 0 changes the keyboard order of the whole page in ways that are hard to follow. Use 0 or -1 and put the content in the right order instead.', 'accesswell' ) ), 'duplicate-id' => array( 'error', '4.1.2', __( 'Duplicate id used by a label or ARIA', 'accesswell' ), __( 'Labels and ARIA attributes point to elements by id. When two elements share that id, the wrong one may be read out. Make each id unique.', 'accesswell' ) ), 'svg-name' => array( 'warning', '1.1.1', __( 'Meaningful SVG has no text alternative', 'accesswell' ), __( 'An SVG with role="img" needs a title element or an aria-label describing it.', 'accesswell' ) ), ); } /** * Rules in the shape the engine uses. * * @return array */ public static function for_script() { $out = array(); $disabled = Accesswell_Settings::get()['skip_rules']; foreach ( self::all() as $id => $rule ) { if ( in_array( $id, $disabled, true ) ) { continue; } $out[ $id ] = array( 'impact' => $rule[0], 'wcag' => $rule[1], 'title' => $rule[2], 'help' => $rule[3], 'url' => self::wcag_url( $rule[1] ), ); } return $out; } /** * Strings the engine adds to some messages. * * @return array */ public static function texts() { return array( /* translators: 1: measured contrast ratio, 2: required ratio */ 'contrast' => __( 'Contrast is %1$s:1; it needs at least %2$s:1.', 'accesswell' ), /* translators: 1: previous heading level, 2: this heading level */ 'headingSkip' => __( 'It goes from h%1$s to h%2$s.', 'accesswell' ), /* translators: %s: link text */ 'linkText' => __( 'Link text: "%s".', 'accesswell' ), 'placeholderOnly' => __( 'It only has placeholder text.', 'accesswell' ), /* translators: %s: id value */ 'duplicateId' => __( 'id="%s" is used more than once.', 'accesswell' ), ); } /** * @param string $id Rule ID. * @return array|null { impact, wcag, title, help } */ public static function get( $id ) { $all = self::all(); if ( ! isset( $all[ $id ] ) ) { return null; } return array( 'impact' => $all[ $id ][0], 'wcag' => $all[ $id ][1], 'title' => $all[ $id ][2], 'help' => $all[ $id ][3], ); } /** * Link to the WCAG 2.2 Understanding page of a criterion. * * @param string $wcag Criterion number, such as "1.4.3". * @return string */ public static function wcag_url( $wcag ) { $slugs = array( '1.1.1' => 'non-text-content', '1.3.1' => 'info-and-relationships', '1.4.2' => 'audio-control', '1.4.3' => 'contrast-minimum', '1.4.4' => 'resize-text', '2.4.1' => 'bypass-blocks', '2.4.2' => 'page-titled', '2.4.3' => 'focus-order', '2.4.4' => 'link-purpose-in-context', '2.4.6' => 'headings-and-labels', '3.1.1' => 'language-of-page', '4.1.2' => 'name-role-value', ); return isset( $slugs[ $wcag ] ) ? 'https://www.w3.org/WAI/WCAG22/Understanding/' . $slugs[ $wcag ] . '.html' : 'https://www.w3.org/WAI/WCAG22/quickref/'; } }