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().
 	 *