diff --git a/packages/js/e2e-utils-playwright/changelog/e2e-utils-playwright-fix-editor-canvas-locator-gb-20.6 b/packages/js/e2e-utils-playwright/changelog/e2e-utils-playwright-fix-editor-canvas-locator-gb-20.6 new file mode 100644 index 0000000000000..43cbc1cbc611e --- /dev/null +++ b/packages/js/e2e-utils-playwright/changelog/e2e-utils-playwright-fix-editor-canvas-locator-gb-20.6 @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Updated the editor canvas frame locator to support changes in Gutenberg 20.6 diff --git a/plugins/woocommerce/changelog/414-appending-coupon-notices-as-elements b/plugins/woocommerce/changelog/414-appending-coupon-notices-as-elements new file mode 100644 index 0000000000000..a66a579a4e7b6 --- /dev/null +++ b/plugins/woocommerce/changelog/414-appending-coupon-notices-as-elements @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Improved shortcode cart and checkout coupon notices by appending elements instead of text. diff --git a/plugins/woocommerce/changelog/56049-56015-fatal-errors-caused-by-wc_add_aria_label_to_pagination_numbers b/plugins/woocommerce/changelog/56049-56015-fatal-errors-caused-by-wc_add_aria_label_to_pagination_numbers new file mode 100644 index 0000000000000..bc1e661df953c --- /dev/null +++ b/plugins/woocommerce/changelog/56049-56015-fatal-errors-caused-by-wc_add_aria_label_to_pagination_numbers @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Avoid fatal by casting page number to integer \ No newline at end of file diff --git a/plugins/woocommerce/changelog/56059-email-accent-color b/plugins/woocommerce/changelog/56059-email-accent-color new file mode 100644 index 0000000000000..55f422c290e29 --- /dev/null +++ b/plugins/woocommerce/changelog/56059-email-accent-color @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix email accent color causing invisible text in emails diff --git a/plugins/woocommerce/changelog/56136-fix-wc_delete_transients b/plugins/woocommerce/changelog/56136-fix-wc_delete_transients new file mode 100644 index 0000000000000..d4376674144cd --- /dev/null +++ b/plugins/woocommerce/changelog/56136-fix-wc_delete_transients @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fixes an error when `_wc_delete_transients` is called but there aren't any transients stored in DB to delete yet. \ No newline at end of file diff --git a/plugins/woocommerce/changelog/fix-394-secure-HTML-elements b/plugins/woocommerce/changelog/fix-394-secure-HTML-elements new file mode 100644 index 0000000000000..d59290f38afa0 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-394-secure-HTML-elements @@ -0,0 +1,4 @@ +Significance: patch +Type: update + +Replaced concatenated string-based HTML elements in JS with createElement(). diff --git a/plugins/woocommerce/changelog/fix-product-editor-xss b/plugins/woocommerce/changelog/fix-product-editor-xss new file mode 100644 index 0000000000000..dd9f83099c4b4 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-product-editor-xss @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix an xss vulnerability in the cart & checkout blocks diff --git a/plugins/woocommerce/changelog/fix-textdomain-loading-warning-in-woocommerce-9-80-beta-1 b/plugins/woocommerce/changelog/fix-textdomain-loading-warning-in-woocommerce-9-80-beta-1 new file mode 100644 index 0000000000000..6e2cdb5b959d5 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-textdomain-loading-warning-in-woocommerce-9-80-beta-1 @@ -0,0 +1,4 @@ +Significance: patch +Type: tweak + +Switch from using FeaturesUtil to get_option for the Email Editor Integration package diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/index.tsx b/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/index.tsx index c15e40e4871a9..4f977dd7385f2 100644 --- a/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/index.tsx +++ b/plugins/woocommerce/client/blocks/assets/js/base/components/product-name/index.tsx @@ -1,7 +1,6 @@ /** * External dependencies */ -import { decodeEntities } from '@wordpress/html-entities'; import clsx from 'clsx'; import type { AnchorHTMLAttributes, HTMLAttributes } from 'react'; @@ -55,9 +54,6 @@ export const ProductName = ( { }: ProductNameProps ): JSX.Element => { const classes = clsx( 'wc-block-components-product-name', className ); const DisabledTagName = disabledTagName as DisabledTagNameType; - // This HTML is safe because the store API runs titles through `wp_kses_post()` which removes dangerous HTML tags. - // Ref: https://github.com/woocommerce/woocommerce/blob/trunk/src/StoreApi/Schemas/V1/ProductSchema.php#L100 - const decodedName = decodeEntities( name ); if ( disabled ) { const disabledProps = props as HTMLAttributes< @@ -69,7 +65,7 @@ export const ProductName = ( { { ...disabledProps } // eslint-disable-next-line react/no-danger dangerouslySetInnerHTML={ { - __html: decodedName, + __html: name, } } /> ); @@ -82,7 +78,7 @@ export const ProductName = ( { { ...props } // eslint-disable-next-line react/no-danger dangerouslySetInnerHTML={ { - __html: decodedName, + __html: name, } } style={ style } /> diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/read-more/trim-html.js b/plugins/woocommerce/client/blocks/assets/js/base/components/read-more/trim-html.js index b0700788e7ea6..1d23c05d60a3a 100644 --- a/plugins/woocommerce/client/blocks/assets/js/base/components/read-more/trim-html.js +++ b/plugins/woocommerce/client/blocks/assets/js/base/components/read-more/trim-html.js @@ -105,12 +105,12 @@ export function trimHtml( html, options ) { row = charArr.slice( 0, cut ).join( '' ) + suffix; if ( moreLink ) { - row += - '' + - moreText + - ''; + const link = document.createElement( 'a' ); + link.href = moreLink; + link.style.display = 'inline'; + link.textContent = moreText; + + row += link.outerHTML; } sum = limit; diff --git a/plugins/woocommerce/client/legacy/js/admin/meta-boxes-coupon.js b/plugins/woocommerce/client/legacy/js/admin/meta-boxes-coupon.js index 115417eb48fb7..f1bd10a3db615 100644 --- a/plugins/woocommerce/client/legacy/js/admin/meta-boxes-coupon.js +++ b/plugins/woocommerce/client/legacy/js/admin/meta-boxes-coupon.js @@ -38,14 +38,19 @@ jQuery(function( $ ) { } }, - /** - * Insert generate coupon code button HTML. - */ - insert_generate_coupon_code_button: function() { - $( '.post-type-shop_coupon' ).find( '#title' ).after( - '' + woocommerce_admin_meta_boxes_coupon.generate_button_text + '' - ); - }, + /** + * Insert generate coupon code button HTML. + */ + insert_generate_coupon_code_button: function () { + const $title = $('.post-type-shop_coupon').find('#title'); + const button = document.createElement('a'); + button.href = '#'; + button.className = 'button generate-coupon-code'; + button.textContent = + woocommerce_admin_meta_boxes_coupon.generate_button_text; + + $title.after(button); + }, /** * Generate a random coupon code diff --git a/plugins/woocommerce/client/legacy/js/admin/wc-shipping-zone-methods.js b/plugins/woocommerce/client/legacy/js/admin/wc-shipping-zone-methods.js index 7b1d10add0b35..95b7196577093 100644 --- a/plugins/woocommerce/client/legacy/js/admin/wc-shipping-zone-methods.js +++ b/plugins/woocommerce/client/legacy/js/admin/wc-shipping-zone-methods.js @@ -104,7 +104,6 @@ $( document.body ).on( 'wc_backbone_modal_next_response', this.onAddShippingMethodSubmitted ); $( document.body ).on( 'wc_backbone_modal_before_remove', this.onCloseConfigureShippingMethod ); $( document.body ).on( 'wc_backbone_modal_back_response', this.onConfigureShippingMethodBack ); - $( document.body ).on( 'change', '.wc-shipping-zone-method-selector select', this.onChangeShippingMethodSelector ); $( document.body ).on( 'click', '.wc-shipping-zone-postcodes-toggle', this.onTogglePostcodes ); $( document.body ).on( 'wc_backbone_modal_validation', { view: this }, this.validateFormArguments ); $( document.body ).on( 'wc_backbone_modal_loaded', { view: this }, this.onModalLoaded ); @@ -751,11 +750,6 @@ } } }, - onChangeShippingMethodSelector: function() { - var description = $( this ).find( 'option:selected' ).data( 'description' ); - $( this ).parent().find( '.wc-shipping-zone-method-description' ).remove(); - $( this ).after( '
' + msg + '
' ); - } else { - $coupon_error_el = html_element; + + $coupon_error_el = $('', {
+ class: 'coupon-error-notice',
+ id: 'coupon-error-notice',
+ text: msg
+ });
}
if ( is_live_region ) {
$coupon_error_el.attr( 'role', 'alert' );
}
-
+
$target.find( '#coupon_code' )
.addClass( 'has-error' )
.attr( 'aria-invalid', 'true' )
.attr( 'aria-describedby', 'coupon-error-notice' );
$target.append( $coupon_error_el );
- };
+ };
/**
* Object to handle AJAX calls for cart shipping changes.
@@ -280,7 +282,7 @@ jQuery( function ( $ ) {
$target.attr( 'aria-expanded', $form.is( ':visible' ) ? 'true' : 'false' );
}, 0 );
} );
-
+
$( 'select.country_to_state, input.country_to_state' ).trigger(
'change'
);
@@ -315,7 +317,7 @@ jQuery( function ( $ ) {
dataType: 'html',
success: function ( response ) {
update_cart_totals_div( response );
-
+
var newCurrentTarget = document.getElementById( event.currentTarget.id );
if ( newCurrentTarget ) {
@@ -600,17 +602,17 @@ jQuery( function ( $ ) {
'.woocommerce-error, .woocommerce-message, .woocommerce-info, ' +
'.is-error, .is-info, .is-success, .coupon-error-notice'
).remove();
-
+
// We only want to show coupon notices if they are not errors.
// Coupon errors are shown under the input.
if ( response.indexOf( 'woocommerce-error' ) === -1 && response.indexOf( 'is-error' ) === -1 ) {
- show_notice( response );
+ show_notice( response );
} else {
var $coupon_wrapper = $text_field.closest( '.coupon' );
if ( $coupon_wrapper.length > 0 ) {
show_coupon_error( response, $coupon_wrapper, false );
- }
+ }
}
$( document.body ).trigger( 'applied_coupon', [
diff --git a/plugins/woocommerce/client/legacy/js/frontend/checkout.js b/plugins/woocommerce/client/legacy/js/frontend/checkout.js
index 901184a4b0242..8ff09ac3feedb 100644
--- a/plugins/woocommerce/client/legacy/js/frontend/checkout.js
+++ b/plugins/woocommerce/client/legacy/js/frontend/checkout.js
@@ -621,29 +621,39 @@ jQuery( function( $ ) {
$( document.body ).trigger( 'checkout_error' , [ error_message ] );
},
wrapMessagesInsideLink: function( $msgs ) {
- $( 'li[data-id]', $msgs ).each( function() {
- var $this = $( this );
-
- $this.wrapInner( '' );
+ $msgs.find( 'li[data-id]' ).each( function() {
+ const $this = $( this );
+ const dataId = $this.attr( 'data-id' );
+ if ( dataId ) {
+ const $link = $('', {
+ href: '#' + dataId,
+ html: $this.html()
+ } );
+ $this.empty().append( $link );
+ }
} );
return $msgs;
},
show_inline_errors: function( $messages ) {
$messages.find( 'li[data-id]' ).each( function() {
- var $this = $( this );
- var dataId = $this.attr( 'data-id' );
- var $field = $( '#' + dataId );
+ const $this = $( this );
+ const dataId = $this.attr( 'data-id' );
+ const $field = $( '#' + dataId );
if ( $field.length === 1 ) {
- var descriptionId = dataId + '_description';
- var msg = $this.text().trim();
- var $formRow = $field.closest( '.form-row' );
-
- $formRow.append( '' + msg + '' );
+
+ $('', {
+ class: 'coupon-error-notice',
+ id: 'coupon-error-notice',
+ role: 'alert',
+ text: msg
+ }).appendTo($target);
},
remove_coupon_error: function( evt ) {
$( evt.currentTarget )
diff --git a/plugins/woocommerce/includes/wc-core-functions.php b/plugins/woocommerce/includes/wc-core-functions.php
index d3bfef1d4dd0c..a767d668642ad 100644
--- a/plugins/woocommerce/includes/wc-core-functions.php
+++ b/plugins/woocommerce/includes/wc-core-functions.php
@@ -2723,13 +2723,13 @@ function _wc_delete_transients( $transients ) {
}
// Limit the number of items in a single query to avoid exceeding database query parameter limits.
- if ( count( $transients) > 199 ) {
+ if ( count( $transients ) > 199 ) {
// Process in smaller chunks to reduce memory usage.
$chunks = array_chunk( $transients, 100 );
$success = true;
foreach ( $chunks as $chunk ) {
- $result = wc_delete_transients( $chunk );
+ $result = _wc_delete_transients( $chunk );
if ( ! $result ) {
$success = false;
}
@@ -2754,6 +2754,11 @@ function _wc_delete_transients( $transients ) {
);
}
+ if ( empty( $options_to_clear ) ) {
+ // If there are no options to clear, return true immediately.
+ return true;
+ }
+
// Use a single query for better performance.
$wpdb->query(
$wpdb->prepare(
@@ -2764,7 +2769,7 @@ function _wc_delete_transients( $transients ) {
// Lets clear our options data from the cache.
// We can batch delete if available, introduced in WP 6.0.0.
- if ( ! wp_installing() && ! empty( $options_to_clear ) ) {
+ if ( ! wp_installing() ) {
if ( function_exists( 'wp_cache_delete_multiple' ) ) {
wp_cache_delete_multiple( $options_to_clear, 'options' );
} else {
diff --git a/plugins/woocommerce/includes/wc-template-functions.php b/plugins/woocommerce/includes/wc-template-functions.php
index 878e409d10bd8..239d6a049e9ee 100644
--- a/plugins/woocommerce/includes/wc-template-functions.php
+++ b/plugins/woocommerce/includes/wc-template-functions.php
@@ -4411,7 +4411,7 @@ function wc_add_aria_label_to_pagination_numbers( $html, $args ) {
continue;
}
- $p->set_attribute( 'aria-label', $page_text . ' ' . number_format_i18n( $n ) );
+ $p->set_attribute( 'aria-label', $page_text . ' ' . number_format_i18n( (int) $n ) );
++$n;
}
diff --git a/plugins/woocommerce/src/Internal/Email/EmailColors.php b/plugins/woocommerce/src/Internal/Email/EmailColors.php
index 886a4c58da250..c4a1b28f52c0b 100644
--- a/plugins/woocommerce/src/Internal/Email/EmailColors.php
+++ b/plugins/woocommerce/src/Internal/Email/EmailColors.php
@@ -40,8 +40,8 @@ public static function get_default_colors() {
&& function_exists( 'wp_get_global_styles' )
) {
$global_styles = wp_get_global_styles( array(), array( 'transforms' => array( 'resolve-variables' ) ) );
- $base_color_global = ! empty( $global_styles['elements']['button']['color']['text'] )
- ? sanitize_hex_color( $global_styles['elements']['button']['color']['text'] ) : '';
+ $base_color_global = ! empty( $global_styles['elements']['button']['color']['background'] )
+ ? sanitize_hex_color( $global_styles['elements']['button']['color']['background'] ) : '';
$bg_color_global = ! empty( $global_styles['color']['background'] )
? sanitize_hex_color( $global_styles['color']['background'] ) : '';
$body_bg_color_global = ! empty( $global_styles['color']['background'] )
diff --git a/plugins/woocommerce/src/Internal/Email/EmailStyleSync.php b/plugins/woocommerce/src/Internal/Email/EmailStyleSync.php
index bfc9d9f3d4c2e..c28f6a36ea422 100644
--- a/plugins/woocommerce/src/Internal/Email/EmailStyleSync.php
+++ b/plugins/woocommerce/src/Internal/Email/EmailStyleSync.php
@@ -152,8 +152,8 @@ protected function get_theme_colors( ?array $override_styles = null ) {
$body_text_color_default = $default_colors['body_text_color_default'];
$footer_text_color_default = $default_colors['footer_text_color_default'];
- $base_color = ! empty( $global_styles['elements']['button']['color']['text'] )
- ? sanitize_hex_color( $global_styles['elements']['button']['color']['text'] )
+ $base_color = ! empty( $global_styles['elements']['button']['color']['background'] )
+ ? sanitize_hex_color( $global_styles['elements']['button']['color']['background'] )
: $base_color_default;
$bg_color = ! empty( $global_styles['color']['background'] )
diff --git a/plugins/woocommerce/src/Internal/EmailEditor/Integration.php b/plugins/woocommerce/src/Internal/EmailEditor/Integration.php
index ec93d6ab765db..51727cf04f930 100644
--- a/plugins/woocommerce/src/Internal/EmailEditor/Integration.php
+++ b/plugins/woocommerce/src/Internal/EmailEditor/Integration.php
@@ -49,6 +49,14 @@ final public function init(): void {
// If dependencies are not met, do not initialize the email editor integration.
return;
}
+
+ add_action( 'init', array( $this, 'initialize' ) );
+ }
+
+ /**
+ * Initialize the integration.
+ */
+ public function initialize() {
$this->init_hooks();
$this->register_hooks();
}
diff --git a/plugins/woocommerce/src/Internal/EmailEditor/Package.php b/plugins/woocommerce/src/Internal/EmailEditor/Package.php
index 6d9113eb41e5a..f186563fdc020 100644
--- a/plugins/woocommerce/src/Internal/EmailEditor/Package.php
+++ b/plugins/woocommerce/src/Internal/EmailEditor/Package.php
@@ -4,8 +4,6 @@
namespace Automattic\WooCommerce\Internal\EmailEditor;
-use Automattic\WooCommerce\Utilities\FeaturesUtil;
-
defined( 'ABSPATH' ) || exit;
/**
@@ -35,13 +33,15 @@ class Package {
* @internal
*/
final public static function init() {
- self::$package_active = FeaturesUtil::feature_is_enabled( 'block_email_editor' );
+ self::$package_active = get_option( 'woocommerce_feature_block_email_editor_enabled', 'no' ) === 'yes'; // init is called pretty early. Cant use FeaturesUtil.
// we only want to initialize the package if the block editor feature flag is enabled.
if ( ! self::$package_active ) {
return;
}
+ self::initialize();
+
\Automattic\WooCommerce\EmailEditor\Package::init();
self::initialize();
}
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/settings/settings-crud.test.js b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/settings/settings-crud.test.js
index 82374bd1b1d21..644b8e55a6b76 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/settings/settings-crud.test.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/settings/settings-crud.test.js
@@ -1552,7 +1552,7 @@ test.describe( 'Settings API tests: CRUD', () => {
type: 'color',
default: '#720eec',
tip: 'The base color for WooCommerce email templates. Default #720eec
.',
- value: '#000000',
+ value: '#9DFF20',
} ),
] )
);
@@ -1698,11 +1698,11 @@ test.describe( 'Settings API tests: CRUD', () => {
id: 'woocommerce_email_base_color',
label: 'Accent',
description:
- 'Customize the color of your buttons and links. Default #000000
.',
+ 'Customize the color of your buttons and links. Default #9DFF20
.',
type: 'color',
- default: '#000000',
- tip: 'Customize the color of your buttons and links. Default #000000
.',
- value: '#000000',
+ default: '#9DFF20',
+ tip: 'Customize the color of your buttons and links. Default #9DFF20
.',
+ value: '#9DFF20',
} ),
] )
);
diff --git a/plugins/woocommerce/tests/php/includes/wc-core-functions-test.php b/plugins/woocommerce/tests/php/includes/wc-core-functions-test.php
index 994ebd16920b9..43bd08db79465 100644
--- a/plugins/woocommerce/tests/php/includes/wc-core-functions-test.php
+++ b/plugins/woocommerce/tests/php/includes/wc-core-functions-test.php
@@ -257,6 +257,10 @@ public function test_wc_delete_transients() {
$this->assertFalse( get_transient( $transient_name3 ) );
+ // Test with a transient that does not exist.
+ $wc_test_transient_not_existing = 'wc_test_transient_not_existing';
+ $this->assertTrue( _wc_delete_transients( array( $wc_test_transient_not_existing ) ) );
+
// Test with empty input.
$this->assertFalse( _wc_delete_transients( array() ) );
$this->assertFalse( _wc_delete_transients( '' ) );
diff --git a/plugins/woocommerce/tests/php/src/Internal/Email/EmailStyleSyncTest.php b/plugins/woocommerce/tests/php/src/Internal/Email/EmailStyleSyncTest.php
index 9afa3d7034d9a..2271378a8e7c8 100644
--- a/plugins/woocommerce/tests/php/src/Internal/Email/EmailStyleSyncTest.php
+++ b/plugins/woocommerce/tests/php/src/Internal/Email/EmailStyleSyncTest.php
@@ -168,7 +168,7 @@ public function test_get_theme_colors() {
'elements' => [
'button' => [
'color' => [
- 'text' => '#ff0000'
+ 'background' => '#ff0000'
]
],
'caption' => [
' );
- $field
- .attr( 'aria-describedby', descriptionId )
- .attr( 'aria-invalid', 'true' );
+ const descriptionId = dataId + '_description';
+ const msg = $this.text().trim();
+ const $formRow = $field.closest( '.form-row' );
+
+ const errorMessage = document.createElement( 'p' );
+ errorMessage.id = descriptionId;
+ errorMessage.className = 'checkout-inline-error-message';
+ errorMessage.textContent = msg;
+
+ $formRow.appendChild( errorMessage );
+ $field.setAttribute( 'aria-describedby', descriptionId );
+ $field.setAttribute( 'aria-invalid', 'true' );
}
} );
},
@@ -695,7 +705,13 @@ jQuery( function( $ ) {
.addClass( 'has-error' )
.attr( 'aria-invalid', 'true' )
.attr( 'aria-describedby', 'coupon-error-notice' );
- $target.append( '