Checkout: prevent error from get_value method when WC has not been properly initialized (#50692)

* Ensure WC's customer and cart props are initialized

If the customer or cart property of the main WooCommerce class is
accessed before the `woocommerce_init` action has fired, those
properties will be `null` instead of containing their respective
classes, which can cause a fatal error if you then try to access a
method on one of the classes. This makes sure the props will always
return a class.

Fixes #50245

* Revert "Ensure WC's customer and cart props are initialized"

This approach unexpectedly breaks a lot of things...

This reverts commit 310fd2c118.

* Alternate solution

The attempt to fix the problem wholistically ended up causing a lot of
things to break, so this is the band-aid approach instead.

* Add changelog file

* Remove unnecessary assignment to global POST var

This was polluting the results of the new test, causing it to fail.
This commit is contained in:
Corey McKrill 2024-08-26 08:17:36 -07:00 committed by GitHub
parent 30ae60b273
commit 70faf5bba2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 25 additions and 11 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Prevent an error in the WC_Checkout class when WooCommerce has not been properly initialized yet

View File

@ -1357,7 +1357,7 @@ class WC_Checkout {
if ( is_callable( array( $customer_object, "get_$input" ) ) ) { if ( is_callable( array( $customer_object, "get_$input" ) ) ) {
$value = $customer_object->{"get_$input"}(); $value = $customer_object->{"get_$input"}();
} elseif ( $customer_object->meta_exists( $input ) ) { } elseif ( is_callable( array( $customer_object, 'meta_exists' ) ) && $customer_object->meta_exists( $input ) ) {
$value = $customer_object->get_meta( $input, true ); $value = $customer_object->get_meta( $input, true );
} }

View File

@ -46,12 +46,11 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case {
* @param bool $expect_error_message_for_shipping_country True to expect an error to be generated for the shipping country. * @param bool $expect_error_message_for_shipping_country True to expect an error to be generated for the shipping country.
*/ */
public function test_validate_posted_data_adds_error_for_non_existing_country( $ship_to_different_address, $expect_error_message_for_shipping_country ) { public function test_validate_posted_data_adds_error_for_non_existing_country( $ship_to_different_address, $expect_error_message_for_shipping_country ) {
$_POST = array( $data = array(
'billing_country' => 'XX', 'billing_country' => 'XX',
'shipping_country' => 'YY', 'shipping_country' => 'YY',
'ship_to_different_address' => $ship_to_different_address, 'ship_to_different_address' => $ship_to_different_address,
); );
$data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing
add_filter( add_filter(
'woocommerce_cart_needs_shipping_address', 'woocommerce_cart_needs_shipping_address',
@ -75,12 +74,11 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case {
* @testdox the customer notes are correctly sanitized. * @testdox the customer notes are correctly sanitized.
*/ */
public function test_order_notes() { public function test_order_notes() {
$_POST = array( $data = array(
'ship_to_different_address' => false, 'ship_to_different_address' => false,
'order_comments' => '<a href="http://attackerpage.com/csrf.html">This text should not save inside an anchor.</a><script>alert("alert")</script>', 'order_comments' => '<a href="http://attackerpage.com/csrf.html">This text should not save inside an anchor.</a><script>alert("alert")</script>',
'payment_method' => 'bacs', 'payment_method' => 'bacs',
); );
$data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing
$errors = new WP_Error(); $errors = new WP_Error();
@ -108,12 +106,11 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case {
* @param bool $ship_to_different_address True to simulate shipping to a different address than the billing address. * @param bool $ship_to_different_address True to simulate shipping to a different address than the billing address.
*/ */
public function test_validate_posted_data_does_not_add_error_for_existing_country( $ship_to_different_address ) { public function test_validate_posted_data_does_not_add_error_for_existing_country( $ship_to_different_address ) {
$_POST = array( $data = array(
'billing_country' => 'ES', 'billing_country' => 'ES',
'shipping_country' => 'ES', 'shipping_country' => 'ES',
'ship_to_different_address' => $ship_to_different_address, 'ship_to_different_address' => $ship_to_different_address,
); );
$data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing
$errors = new WP_Error(); $errors = new WP_Error();
@ -132,12 +129,11 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case {
* @param bool $ship_to_different_address True to simulate shipping to a different address than the billing address. * @param bool $ship_to_different_address True to simulate shipping to a different address than the billing address.
*/ */
public function test_validate_posted_data_does_not_add_error_for_empty_country( $ship_to_different_address ) { public function test_validate_posted_data_does_not_add_error_for_empty_country( $ship_to_different_address ) {
$_POST = array( $data = array(
'billing_country' => '', 'billing_country' => '',
'shipping_country' => '', 'shipping_country' => '',
'ship_to_different_address' => $ship_to_different_address, 'ship_to_different_address' => $ship_to_different_address,
); );
$data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing
$errors = new WP_Error(); $errors = new WP_Error();
@ -186,12 +182,11 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case {
) )
); );
$_POST = array( $data = array(
'billing_country' => $country, 'billing_country' => $country,
'shipping_country' => $country, 'shipping_country' => $country,
'ship_to_different_address' => false, 'ship_to_different_address' => false,
); );
$data = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing
$errors = new WP_Error(); $errors = new WP_Error();
@ -202,5 +197,20 @@ class WC_Checkout_Test extends \WC_Unit_Test_Case {
$errors->get_error_message( 'shipping' ) $errors->get_error_message( 'shipping' )
); );
} }
/**
* @testdox If the WooCommerce class's customer object is null (like if WC has not been fully initialized yet),
* calling WC_Checkout::get_value should not throw an error.
*/
public function test_get_value_no_error_on_null_customer() {
$sut = WC_Checkout::instance();
$orig_customer = WC()->customer;
WC()->customer = null;
$this->assertNull( $sut->get_value( 'billing_country' ) );
WC()->customer = $orig_customer;
}
} }