Commit ac9331f7309 for woocommerce
commit ac9331f730976544d07069ae5c3706f3a4eaac96
Author: SH Sajal Chowdhury <72102985+shsajalchowdhury@users.noreply.github.com>
Date: Sat May 16 16:10:20 2026 +0600
Harden defensive validation of extension-provided actions in order-details.php template (#64492)
diff --git a/plugins/woocommerce/changelog/64492-fix-harden-order-details-actions-validation b/plugins/woocommerce/changelog/64492-fix-harden-order-details-actions-validation
new file mode 100644
index 00000000000..a9416cfdad8
--- /dev/null
+++ b/plugins/woocommerce/changelog/64492-fix-harden-order-details-actions-validation
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Add defensive validation to order action links in order-details.php template to handle malformed entries from third-party extensions.
\ No newline at end of file
diff --git a/plugins/woocommerce/includes/wc-account-functions.php b/plugins/woocommerce/includes/wc-account-functions.php
index 31a137c3e30..459f4341c48 100644
--- a/plugins/woocommerce/includes/wc-account-functions.php
+++ b/plugins/woocommerce/includes/wc-account-functions.php
@@ -299,6 +299,10 @@ function wc_get_account_orders_actions( $order ) {
$order = wc_get_order( $order_id );
}
+ if ( ! $order instanceof WC_Order ) {
+ return array();
+ }
+
$actions = array(
'pay' => array(
'url' => $order->get_checkout_payment_url(),
@@ -337,7 +341,30 @@ function wc_get_account_orders_actions( $order ) {
unset( $actions['cancel'] );
}
- return apply_filters( 'woocommerce_my_account_my_orders_actions', $actions, $order );
+ /**
+ * Filters the actions available for an order on the My Account orders list.
+ *
+ * @since 2.0.0
+ *
+ * @param array $actions Array of order actions, keyed by action slug. Each action is an array with 'url' and 'name' keys.
+ * @param WC_Order $order Order instance.
+ */
+ $actions = apply_filters( 'woocommerce_my_account_my_orders_actions', $actions, $order );
+
+ if ( ! is_array( $actions ) ) {
+ return array();
+ }
+
+ // Filter out malformed action entries from third-party extensions.
+ return array_filter(
+ $actions,
+ static function ( $action ) {
+ return is_array( $action )
+ && isset( $action['name'], $action['url'] )
+ && is_string( $action['name'] )
+ && is_string( $action['url'] );
+ }
+ );
}
/**
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 762bf98b1e8..73ae5c0095f 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -33285,12 +33285,6 @@ parameters:
count: 1
path: includes/walkers/class-wc-product-cat-list-walker.php
- -
- message: '#^@param WC_Order \$order does not accept actual type of parameter\: WC_Order\|WC_Order_Refund\|false\.$#'
- identifier: parameter.phpDocType
- count: 1
- path: includes/wc-account-functions.php
-
-
message: '#^Access to an undefined property WooCommerce\:\:\$payment_gateways\.$#'
identifier: property.notFound
@@ -33321,42 +33315,6 @@ parameters:
count: 2
path: includes/wc-account-functions.php
- -
- message: '#^Cannot call method get_cancel_order_url\(\) on WC_Order\|WC_Order_Refund\|false\.$#'
- identifier: method.nonObject
- count: 1
- path: includes/wc-account-functions.php
-
- -
- message: '#^Cannot call method get_checkout_payment_url\(\) on WC_Order\|WC_Order_Refund\|false\.$#'
- identifier: method.nonObject
- count: 1
- path: includes/wc-account-functions.php
-
- -
- message: '#^Cannot call method get_order_number\(\) on WC_Order\|WC_Order_Refund\|false\.$#'
- identifier: method.nonObject
- count: 3
- path: includes/wc-account-functions.php
-
- -
- message: '#^Cannot call method get_status\(\) on WC_Order\|WC_Order_Refund\|false\.$#'
- identifier: method.nonObject
- count: 1
- path: includes/wc-account-functions.php
-
- -
- message: '#^Cannot call method get_view_order_url\(\) on WC_Order\|WC_Order_Refund\|false\.$#'
- identifier: method.nonObject
- count: 1
- path: includes/wc-account-functions.php
-
- -
- message: '#^Cannot call method needs_payment\(\) on WC_Order\|WC_Order_Refund\|false\.$#'
- identifier: method.nonObject
- count: 1
- path: includes/wc-account-functions.php
-
-
message: '#^Parameter \#2 \$value of function wc_get_endpoint_url expects string, int given\.$#'
identifier: argument.type
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/account/functions.php b/plugins/woocommerce/tests/legacy/unit-tests/account/functions.php
index 32ed29aeea2..d7674377b8e 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/account/functions.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/account/functions.php
@@ -202,6 +202,71 @@ class WC_Tests_Account_Functions extends WC_Unit_Test_Case {
$order->delete( true );
}
+ /**
+ * Test wc_get_account_orders_actions() filters out malformed entries from the filter.
+ *
+ * @since 10.9.0
+ */
+ public function test_wc_get_account_orders_actions_filters_malformed_entries() {
+ $order = WC_Helper_Order::create_order();
+
+ // Add malformed entries via the filter.
+ add_filter(
+ 'woocommerce_my_account_my_orders_actions',
+ static function ( $actions ) {
+ $actions['invalid_bool'] = false;
+ $actions['invalid_string'] = 'not-an-array';
+ $actions['missing_url'] = array( 'name' => 'No URL' );
+ $actions['missing_name'] = array( 'url' => 'https://example.com' );
+ $actions['non_string_url'] = array(
+ 'name' => 'Test',
+ 'url' => 123,
+ );
+ $actions['non_string_name'] = array(
+ 'name' => true,
+ 'url' => 'https://example.com',
+ );
+ return $actions;
+ }
+ );
+
+ $result = wc_get_account_orders_actions( $order->get_id() );
+
+ // All malformed entries should be removed, only valid actions remain.
+ $this->assertArrayNotHasKey( 'invalid_bool', $result );
+ $this->assertArrayNotHasKey( 'invalid_string', $result );
+ $this->assertArrayNotHasKey( 'missing_url', $result );
+ $this->assertArrayNotHasKey( 'missing_name', $result );
+ $this->assertArrayNotHasKey( 'non_string_url', $result );
+ $this->assertArrayNotHasKey( 'non_string_name', $result );
+
+ // Valid original actions should still be present.
+ $this->assertArrayHasKey( 'view', $result );
+ $this->assertArrayHasKey( 'pay', $result );
+
+ $order->delete( true );
+ }
+
+ /**
+ * Test wc_get_account_orders_actions() returns empty array when filter returns non-array.
+ *
+ * @since 10.9.0
+ */
+ public function test_wc_get_account_orders_actions_returns_empty_for_non_array_filter() {
+ $order = WC_Helper_Order::create_order();
+
+ add_filter(
+ 'woocommerce_my_account_my_orders_actions',
+ '__return_false'
+ );
+
+ $result = wc_get_account_orders_actions( $order->get_id() );
+
+ $this->assertSame( array(), $result );
+
+ $order->delete( true );
+ }
+
/**
* Test wc_get_account_formatted_address().
*