Adding accessible markup to sale price. (#44413)

* Adding accessible markup to sale price. See #31099

This PR adds accessible markup to the sale price.

A user who only uses screen reader software can now hear and understand the original price as well as the current price.

This is important for accessibility.

Full issue: https://github.com/woocommerce/woocommerce/issues/31099

* Improving sale price string formatting & localization #31099

This PR merges in feedback from the WooCommerce team.

* Improving string translation & output. Giving RTL languages more customization with the price in the translatable string.
* Formatting regular price & sale price at the top and then inserting into the HTML below. This prevents some sloppy logic where you might print out a blank del or ins tag.

* Swapping esc_html & sprintf #31099

Reversed the esc_html() and sprintf(). This is intentional because if translations accidentally include some HTML, that could break things.

Also, stripping HTML tags in $formatted_regular_price so that the end result in the screen-reader-text span is just plain text.

* Adjusting white space #31099

Mostly removing white space for the lint checker

* Adding translator comments #31099

Adding translator comments for lint

* Add changelog

* Fix some PHPCS violations

* Fix unit tests

* Adjust E2E test

---------

Co-authored-by: Jorge Torres <jorge.torres@automattic.com>
This commit is contained in:
Patrick Rauland 2024-03-13 17:43:44 -06:00 committed by GitHub
parent b3c328d4e4
commit 72f75edf58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 30 additions and 5 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: enhancement
Improve accessibility of sale price markup.

View File

@ -1290,7 +1290,28 @@ function wc_format_stock_quantity_for_display( $stock_quantity, $product ) {
* @return string
*/
function wc_format_sale_price( $regular_price, $sale_price ) {
$price = '<del aria-hidden="true">' . ( is_numeric( $regular_price ) ? wc_price( $regular_price ) : $regular_price ) . '</del> <ins>' . ( is_numeric( $sale_price ) ? wc_price( $sale_price ) : $sale_price ) . '</ins>';
// Format the prices.
$formatted_regular_price = is_numeric( $regular_price ) ? wc_price( $regular_price ) : $regular_price;
$formatted_sale_price = is_numeric( $sale_price ) ? wc_price( $sale_price ) : $sale_price;
// Strikethrough pricing.
$price = '<del aria-hidden="true">' . $formatted_regular_price . '</del> ';
// For accessibility (a11y) we'll also display that information to screen readers.
$price .= '<span class="screen-reader-text">';
// translators: %s is a product's regular price.
$price .= esc_html( sprintf( __( 'Original price was: %s.', 'woocommerce' ), wp_strip_all_tags( $formatted_regular_price ) ) );
$price .= '</span>';
// Add the sale price.
$price .= '<ins aria-hidden="true">' . $formatted_sale_price . '</ins>';
// For accessibility (a11y) we'll also display that information to screen readers.
$price .= '<span class="screen-reader-text">';
// translators: %s is a product's current (sale) price.
$price .= esc_html( sprintf( __( 'Current price is: %s.', 'woocommerce' ), wp_strip_all_tags( $formatted_sale_price ) ) );
$price .= '</span>';
return apply_filters( 'woocommerce_format_sale_price', $price, $regular_price, $sale_price );
}

View File

@ -163,7 +163,7 @@ baseTest.describe( 'Products > Edit Product', () => {
.soft( page.locator( 'p' ).locator( 'del' ) )
.toHaveText( `$${ expectedRegularPrice }` );
await expect
.soft( page.locator( 'p' ).getByRole( 'insertion' ) )
.soft( page.locator( 'p' ).locator( 'ins' ) )
.toHaveText( `$${ expectedSalePrice }` );
await expect
.soft( page.getByText( `${ expectedStockQty } in stock` ) )

View File

@ -932,7 +932,7 @@ class WC_Tests_Formatting_Functions extends WC_Unit_Test_Case {
* @since 3.3.0
*/
public function test_wc_format_sale_price() {
$this->assertEquals( '<del aria-hidden="true"><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>10.00</bdi></span></del> <ins><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>5.00</bdi></span></ins>', wc_format_sale_price( '10', '5' ) );
$this->assertEquals( '<del aria-hidden="true"><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>10.00</bdi></span></del> <span class="screen-reader-text">Original price was: &#036;10.00.</span><ins aria-hidden="true"><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>5.00</bdi></span></ins><span class="screen-reader-text">Current price is: &#036;5.00.</span>', wc_format_sale_price( '10', '5' ) );
}
/**

View File

@ -262,11 +262,11 @@ class WC_Tests_Product_Data extends WC_Unit_Test_Case {
$product = wc_get_product( $product1_id );
$this->assertEquals( $product1_id, $product->get_id() );
$this->assertEquals( '<del aria-hidden="true"><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>10.00</bdi></span></del> <ins><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>7.00</bdi></span></ins>', $product->get_price_html() );
$this->assertEquals( '<del aria-hidden="true"><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>10.00</bdi></span></del> <span class="screen-reader-text">Original price was: &#036;10.00.</span><ins aria-hidden="true"><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>7.00</bdi></span></ins><span class="screen-reader-text">Current price is: &#036;7.00.</span>', $product->get_price_html() );
$product = wc_get_product( $product2_id );
$this->assertEquals( $product2_id, $product->get_id() );
$this->assertEquals( '<del aria-hidden="true"><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>20.00</bdi></span></del> <ins><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>16.00</bdi></span></ins>', $product->get_price_html() );
$this->assertEquals( '<del aria-hidden="true"><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>20.00</bdi></span></del> <span class="screen-reader-text">Original price was: &#036;20.00.</span><ins aria-hidden="true"><span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">&#36;</span>16.00</bdi></span></ins><span class="screen-reader-text">Current price is: &#036;16.00.</span>', $product->get_price_html() );
$product = wc_get_product( $product3_id );
$this->assertEquals( $product3_id, $product->get_id() );