[Accessibility] Provide screen readers with product sorting status message (#50573)
* Update result-count template to display orderby message * Update result count live region if products are sorted * Bump result-count template version * Remove additional full stop. * Fix docblock spacings * Remove jQuery code from sort by live region logic * Validate filter result type --------- Co-authored-by: Tom Cafferkey <tjcafferkey@gmail.com>
This commit is contained in:
parent
19aac5f6fb
commit
f8677c45d1
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: add
|
||||
|
||||
Provide screen readers with product sorting status message.
|
|
@ -148,7 +148,14 @@ jQuery( function ( $ ) {
|
|||
} );
|
||||
});
|
||||
|
||||
document.addEventListener( 'DOMContentLoaded' , function() {
|
||||
/**
|
||||
* Focus on the first notice element on the page.
|
||||
*
|
||||
* Populated live regions don't always are announced by screen readers.
|
||||
* This function focus on the first notice message with the role="alert"
|
||||
* attribute to make sure it's announced.
|
||||
*/
|
||||
function focus_populate_live_region() {
|
||||
var noticeClasses = [ 'woocommerce-message', 'woocommerce-error', 'wc-block-components-notice-banner' ];
|
||||
var noticeSelectors = noticeClasses.map( function( className ) {
|
||||
return '.' + className + '[role="alert"]';
|
||||
|
@ -168,4 +175,28 @@ document.addEventListener( 'DOMContentLoaded' , function() {
|
|||
firstNotice.focus();
|
||||
clearTimeout( delayFocusNoticeId );
|
||||
}, 500 );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the sorted by live region.
|
||||
*/
|
||||
function refresh_sorted_by_live_region () {
|
||||
var sorted_by_live_region = document.querySelector( '.woocommerce-result-count[data-is-sorted-by="true"]' );
|
||||
|
||||
if ( sorted_by_live_region ) {
|
||||
var text = sorted_by_live_region.innerHTML;
|
||||
|
||||
var sorted_by_live_region_id = setTimeout( function() {
|
||||
sorted_by_live_region.innerHTML = '';
|
||||
sorted_by_live_region.innerHTML = text;
|
||||
clearTimeout( sorted_by_live_region_id );
|
||||
}, 1000 );
|
||||
}
|
||||
}
|
||||
|
||||
function on_document_ready() {
|
||||
focus_populate_live_region();
|
||||
refresh_sorted_by_live_region();
|
||||
}
|
||||
|
||||
document.addEventListener( 'DOMContentLoaded' , on_document_ready );
|
||||
|
|
|
@ -1480,10 +1480,48 @@ if ( ! function_exists( 'woocommerce_result_count' ) ) {
|
|||
if ( ! wc_get_loop_prop( 'is_paginated' ) || ! woocommerce_products_will_display() ) {
|
||||
return;
|
||||
}
|
||||
$args = array(
|
||||
'total' => wc_get_loop_prop( 'total' ),
|
||||
'per_page' => wc_get_loop_prop( 'per_page' ),
|
||||
'current' => wc_get_loop_prop( 'current_page' ),
|
||||
|
||||
/**
|
||||
* Filters the default orderby option.
|
||||
*
|
||||
* @since 1.6.4
|
||||
*
|
||||
* @param string $default_orderby The default orderby option.
|
||||
*/
|
||||
$default_orderby = apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby', '' ) );
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
$orderby = isset( $_GET['orderby'] ) ? wc_clean( wp_unslash( $_GET['orderby'] ) ) : $default_orderby;
|
||||
|
||||
// If products follow the default order this doesn't need to be informed.
|
||||
$orderby = 'menu_order' === $orderby ? '' : $orderby;
|
||||
|
||||
$orderby = is_string( $orderby ) ? $orderby : '';
|
||||
|
||||
/**
|
||||
* Filters ordered by messages.
|
||||
*
|
||||
* @since 9.3.0
|
||||
*
|
||||
* @param array $orderedby_messages The list of messages per orderby key.
|
||||
*/
|
||||
$catalog_orderedby_options = apply_filters(
|
||||
'woocommerce_catalog_orderedby',
|
||||
array(
|
||||
'menu_order' => __( 'Default sorting', 'woocommerce' ),
|
||||
'popularity' => __( 'Sorted by popularity', 'woocommerce' ),
|
||||
'rating' => __( 'Sorted by average rating', 'woocommerce' ),
|
||||
'date' => __( 'Sorted by latest', 'woocommerce' ),
|
||||
'price' => __( 'Sorted by price: low to high', 'woocommerce' ),
|
||||
'price-desc' => __( 'Sorted by price: high to low', 'woocommerce' ),
|
||||
)
|
||||
);
|
||||
$orderedby = isset( $catalog_orderedby_options[ $orderby ] ) ? $catalog_orderedby_options[ $orderby ] : '';
|
||||
$orderedby = is_string( $orderedby ) ? $orderedby : '';
|
||||
$args = array(
|
||||
'total' => wc_get_loop_prop( 'total' ),
|
||||
'per_page' => wc_get_loop_prop( 'per_page' ),
|
||||
'current' => wc_get_loop_prop( 'current_page' ),
|
||||
'orderedby' => $orderedby,
|
||||
);
|
||||
|
||||
wc_get_template( 'loop/result-count.php', $args );
|
||||
|
|
|
@ -14,26 +14,28 @@
|
|||
*
|
||||
* @see https://woocommerce.com/document/template-structure/
|
||||
* @package WooCommerce\Templates
|
||||
* @version 3.7.0
|
||||
* @version 9.4.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
<p class="woocommerce-result-count">
|
||||
<p class="woocommerce-result-count" <?php echo ( empty( $orderedby ) || 1 === intval( $total ) ) ? '' : 'role="alert" aria-relevant="all" data-is-sorted-by="true"'; ?>>
|
||||
<?php
|
||||
// phpcs:disable WordPress.Security
|
||||
if ( 1 === intval( $total ) ) {
|
||||
_e( 'Showing the single result', 'woocommerce' );
|
||||
} elseif ( $total <= $per_page || -1 === $per_page ) {
|
||||
/* translators: %d: total results */
|
||||
printf( _n( 'Showing all %d result', 'Showing all %d results', $total, 'woocommerce' ), $total );
|
||||
$orderedby_placeholder = empty( $orderedby ) ? '%2$s' : '<span class="screen-reader-text">%2$s</span>';
|
||||
/* translators: 1: total results 2: sorted by */
|
||||
printf( _n( 'Showing all %1$d result', 'Showing all %1$d results', $total, 'woocommerce' ) . $orderedby_placeholder, $total, esc_html( $orderedby ) );
|
||||
} else {
|
||||
$first = ( $per_page * $current ) - $per_page + 1;
|
||||
$last = min( $total, $per_page * $current );
|
||||
/* translators: 1: first result 2: last result 3: total results */
|
||||
printf( _nx( 'Showing %1$d–%2$d of %3$d result', 'Showing %1$d–%2$d of %3$d results', $total, 'with first and last result', 'woocommerce' ), $first, $last, $total );
|
||||
$first = ( $per_page * $current ) - $per_page + 1;
|
||||
$last = min( $total, $per_page * $current );
|
||||
$orderedby_placeholder = empty( $orderedby ) ? '%4$s' : '<span class="screen-reader-text">%4$s</span>';
|
||||
/* translators: 1: first result 2: last result 3: total results 4: sorted by */
|
||||
printf( _nx( 'Showing %1$d–%2$d of %3$d result', 'Showing %1$d–%2$d of %3$d results', $total, 'with first and last result', 'woocommerce' ) . $orderedby_placeholder, $first, $last, $total, esc_html( $orderedby ) );
|
||||
}
|
||||
// phpcs:enable WordPress.Security
|
||||
?>
|
||||
|
|
Loading…
Reference in New Issue