diff --git a/changelog/fix-9716-disputes-api-requests b/changelog/fix-9716-disputes-api-requests new file mode 100644 index 00000000000..10f5387c9b4 --- /dev/null +++ b/changelog/fix-9716-disputes-api-requests @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Performance improvements for Disputes Needing Response task shown in WooCommerce admin. diff --git a/includes/admin/class-wc-payments-admin.php b/includes/admin/class-wc-payments-admin.php index 6509cc90ecb..e7ad01fe210 100644 --- a/includes/admin/class-wc-payments-admin.php +++ b/includes/admin/class-wc-payments-admin.php @@ -1336,6 +1336,7 @@ public function add_transactions_notification_badge() { /** * Gets the number of disputes which need a response. ie have a 'needs_response' or 'warning_needs_response' status. + * Used to display a notification badge on the Payments > Disputes menu item. * * @return int The number of disputes which need a response. */ diff --git a/includes/admin/tasks/class-wc-payments-task-disputes.php b/includes/admin/tasks/class-wc-payments-task-disputes.php index b7212ec7623..7d5ac82faf4 100644 --- a/includes/admin/tasks/class-wc-payments-task-disputes.php +++ b/includes/admin/tasks/class-wc-payments-task-disputes.php @@ -49,6 +49,13 @@ class WC_Payments_Task_Disputes extends Task { */ private $disputes_due_within_1d; + /** + * A memory cache of all disputes needing response. + * + * @var array|null + */ + private $disputes_needing_response = null; + /** * WC_Payments_Task_Disputes constructor. */ @@ -57,13 +64,12 @@ public function __construct() { $this->api_client = \WC_Payments::get_payments_api_client(); $this->database_cache = \WC_Payments::get_database_cache(); parent::__construct(); - $this->init(); } /** * Initialize the task. */ - private function init() { + private function fetch_relevant_disputes() { $this->disputes_due_within_7d = $this->get_disputes_needing_response_within_days( 7 ); $this->disputes_due_within_1d = $this->get_disputes_needing_response_within_days( 1 ); } @@ -83,6 +89,9 @@ public function get_id() { * @return string */ public function get_title() { + if ( null === $this->disputes_needing_response ) { + $this->fetch_relevant_disputes(); + } if ( count( (array) $this->disputes_due_within_7d ) === 1 ) { $dispute = $this->disputes_due_within_7d[0]; $amount = WC_Payments_Utils::interpret_stripe_amount( $dispute['amount'], $dispute['currency'] ); @@ -275,6 +284,9 @@ public function is_complete() { * @return bool */ public function can_view() { + if ( null === $this->disputes_needing_response ) { + $this->fetch_relevant_disputes(); + } return count( (array) $this->disputes_due_within_7d ) > 0; } @@ -322,15 +334,24 @@ private function get_disputes_needing_response_within_days( $num_days ) { * @return array|null Array of disputes awaiting a response. Null on failure. */ private function get_disputes_needing_response() { - return $this->database_cache->get_or_add( + if ( null !== $this->disputes_needing_response ) { + return $this->disputes_needing_response; + } + + $this->disputes_needing_response = $this->database_cache->get_or_add( Database_Cache::ACTIVE_DISPUTES_KEY, function () { - $response = $this->api_client->get_disputes( - [ - 'pagesize' => 50, - 'search' => [ 'warning_needs_response', 'needs_response' ], - ] - ); + try { + $response = $this->api_client->get_disputes( + [ + 'pagesize' => 50, + 'search' => [ 'warning_needs_response', 'needs_response' ], + ] + ); + } catch ( \Exception $e ) { + // Ensure an array is always returned, even if the API call fails. + return []; + } $active_disputes = $response['data'] ?? []; @@ -347,8 +368,9 @@ function ( $a, $b ) { return $active_disputes; }, - // We'll consider all array values to be valid as the cache is only invalidated when it is deleted or it expires. 'is_array' ); + + return $this->disputes_needing_response; } } diff --git a/includes/class-wc-payments-tasks.php b/includes/class-wc-payments-tasks.php index ee3feacff48..b0b01e22896 100644 --- a/includes/class-wc-payments-tasks.php +++ b/includes/class-wc-payments-tasks.php @@ -21,7 +21,11 @@ class WC_Payments_Tasks { * WC_Payments_Admin_Tasks constructor. */ public static function init() { - include_once WCPAY_ABSPATH . 'includes/admin/tasks/class-wc-payments-task-disputes.php'; + // As WooCommerce Onboarding tasks need to hook into 'init' and requires an API call. + // We only add this task for users who can manage_woocommerce / view the task. + if ( ! current_user_can( 'manage_woocommerce' ) ) { + return; + } add_action( 'init', [ __CLASS__, 'add_task_disputes_need_response' ] ); } @@ -31,9 +35,11 @@ public static function init() { */ public static function add_task_disputes_need_response() { $account_service = WC_Payments::get_account_service(); - if ( ! $account_service || ! $account_service->is_stripe_account_valid() ) { + // The task is not required if the account is not connected, under review, or rejected. + if ( ! $account_service || ! $account_service->is_stripe_account_valid() || $account_service->is_account_under_review() || $account_service->is_account_rejected() ) { return; } + include_once WCPAY_ABSPATH . 'includes/admin/tasks/class-wc-payments-task-disputes.php'; // 'extended' = 'Things to do next' task list on WooCommerce > Home. TaskLists::add_task( 'extended', new WC_Payments_Task_Disputes() ); diff --git a/tests/unit/admin/tasks/test-class-wc-payments-task-disputes.php b/tests/unit/admin/tasks/test-class-wc-payments-task-disputes.php index 43771de278d..729be9743f0 100644 --- a/tests/unit/admin/tasks/test-class-wc-payments-task-disputes.php +++ b/tests/unit/admin/tasks/test-class-wc-payments-task-disputes.php @@ -8,6 +8,7 @@ use WCPay\Constants\Country_Code; use WooCommerce\Payments\Tasks\WC_Payments_Task_Disputes; +require_once WCPAY_ABSPATH . 'includes/admin/tasks/class-wc-payments-task-disputes.php'; /** * WC_Payments_Task_Disputes unit tests. */