Skip to content

Commit dbd1931

Browse files
wjrosaCopilotMayisha
authored
Adding the subscription detached check bulk action (#4507)
* Adding the subscription detached check bulk action * Changelog and readme entries * Unit test * Unit tests * Fix tests * Unit tests * Unit tests * Update includes/admin/class-wc-stripe-subscription-detached-bulk-action.php Co-authored-by: Copilot <[email protected]> * Update includes/admin/class-wc-stripe-subscription-detached-bulk-action.php Co-authored-by: Copilot <[email protected]> * Update includes/compat/class-wc-stripe-subscriptions-helper.php Co-authored-by: Copilot <[email protected]> * Update includes/admin/class-wc-stripe-admin-notices.php Co-authored-by: Copilot <[email protected]> * Fix sanitization order * Update includes/compat/class-wc-stripe-subscriptions-helper.php Co-authored-by: Mayisha <[email protected]> * Change called method after renaming * Adding feedback when there are no detached subscriptions * Make the bulk notice dismissable * Fix notice concat * Moving the redirect call inside the bulk action case --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Mayisha <[email protected]>
1 parent bbd6987 commit dbd1931

9 files changed

+358
-9
lines changed

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
*** Changelog ***
22

33
= 9.8.0 - xxxx-xx-xx =
4+
* Add - Adds a new bulk action option to the subscriptions listing screen to check for detached payment methods
45
* Dev - Use product type constants that were added in WooCommerce 9.7
56
* Dev - Removes the inclusion of the deprecated WC_Stripe_Order class
67
* Add - Introduces a new banner to promote the Optimized Checkout feature in the Stripe settings page for versions 9.8 and above

includes/admin/class-wc-stripe-admin-notices.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public function admin_notices() {
6969
// Check for subscriptions detached from the customer.
7070
if ( WC_Stripe_Subscriptions_Helper::is_subscriptions_enabled() ) {
7171
$this->subscription_check_detachment();
72+
$this->subscription_check_detachment_bulk_action();
7273
}
7374

7475
foreach ( (array) $this->notices as $notice_key => $notice ) {
@@ -512,6 +513,48 @@ public function subscription_check_detachment() {
512513
}
513514
}
514515

516+
/**
517+
* Add a notice to the admin area if there are subscriptions with payment method detached.
518+
*
519+
* @return void
520+
*/
521+
public function subscription_check_detachment_bulk_action() {
522+
if ( isset( $_REQUEST['detached-subscriptions'] ) && 'no' !== get_option( 'wc_stripe_show_subscription_detached_bulk_action_notice' ) ) {
523+
$notice_content = '<p>' . esc_html__( 'No detached subscriptions found.', 'woocommerce-gateway-stripe' ) . '</p>';
524+
$notice_class = 'info';
525+
if ( ! empty( $_REQUEST['detached-subscriptions'] ) ) {
526+
$detached_subs_ids = explode( ',', sanitize_text_field( wp_unslash( $_REQUEST['detached-subscriptions'] ) ) );
527+
$subscriptions = [];
528+
foreach ( $detached_subs_ids as $detached_sub_id ) {
529+
$detached_sub_id = absint( $detached_sub_id );
530+
$subscription = wcs_get_subscription( $detached_sub_id );
531+
if ( ! $subscription instanceof WC_Subscription ) {
532+
continue;
533+
}
534+
$subscriptions[] = WC_Stripe_Subscriptions_Helper::get_detached_payment_data_from_subscription( $subscription );
535+
}
536+
$detached_messages = WC_Stripe_Subscriptions_Helper::build_subscriptions_detached_messages( $subscriptions );
537+
if ( ! empty( $detached_messages ) ) {
538+
$notice_content = '<p>';
539+
$notice_content .= wp_kses(
540+
$detached_messages,
541+
[
542+
'a' => [
543+
'href' => [],
544+
'target' => [],
545+
],
546+
'strong' => [],
547+
'br' => [],
548+
]
549+
);
550+
$notice_content .= '</p>';
551+
$notice_class = 'error';
552+
}
553+
}
554+
$this->add_admin_notice( 'subscription_detached_bulk_action', 'notice notice-' . $notice_class, $notice_content, true );
555+
}
556+
}
557+
515558
/**
516559
* Environment check for subscriptions.
517560
*
@@ -593,6 +636,14 @@ public function hide_notices() {
593636
case 'subscriptions':
594637
update_option( 'wc_stripe_show_subscriptions_notice', 'no' );
595638
break;
639+
case 'subscription_detached_bulk_action':
640+
update_option( 'wc_stripe_show_subscription_detached_bulk_action_notice', 'no' );
641+
642+
// Redirect back to the current page without the query param to hide the notice to avoid issues.
643+
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
644+
wp_safe_redirect( remove_query_arg( [ 'wc-stripe-hide-notice', '_wc_stripe_notice_nonce' ], esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) );
645+
}
646+
break;
596647
}
597648
}
598649
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
if ( ! defined( 'ABSPATH' ) ) {
4+
exit;
5+
}
6+
7+
/**
8+
* Class WC_Stripe_Subscription_Detached_Bulk_Action
9+
*/
10+
class WC_Stripe_Subscription_Detached_Bulk_Action {
11+
/**
12+
* Constructor.
13+
*/
14+
public function __construct() {
15+
if ( WC_Stripe_Woo_Compat_Utils::is_custom_orders_table_enabled() ) {
16+
add_filter( 'bulk_actions-woocommerce_page_wc-orders--shop_subscription', [ $this, 'subscriptions_bulk_actions' ] );
17+
add_filter( 'handle_bulk_actions-woocommerce_page_wc-orders--shop_subscription', [ $this, 'handle_subscription_detachment_check' ], 10, 3 );
18+
} else {
19+
add_filter( 'bulk_actions-edit-shop_subscription', [ $this, 'subscriptions_bulk_actions' ] );
20+
add_filter( 'handle_bulk_actions-edit-shop_subscription', [ $this, 'handle_subscription_detachment_check' ], 10, 3 );
21+
}
22+
}
23+
24+
/**
25+
* Add custom bulk action to check for detachment of subscriptions' payment methods.
26+
*
27+
* @param array $bulk_actions An associative array of actions which can be performed on the subscription post type.
28+
* @return array
29+
*/
30+
public function subscriptions_bulk_actions( $bulk_actions ) {
31+
$bulk_actions['check-for-payment-method-detachment'] = __( 'Check for payment method detachment', 'woocommerce-gateway-stripe' );
32+
return $bulk_actions;
33+
}
34+
35+
/**
36+
* Handle the custom bulk action to check for detachment of subscriptions' payment methods.
37+
*
38+
* @param string $redirect_url The URL to redirect to after the action is performed.
39+
* @param string $action The action being performed.
40+
* @param array $post_ids The IDs of the posts being acted upon.
41+
* @return string
42+
*/
43+
public function handle_subscription_detachment_check( $redirect_url, $action, $post_ids ) {
44+
if ( 'check-for-payment-method-detachment' === $action ) {
45+
update_option( 'wc_stripe_show_subscription_detached_bulk_action_notice', 'yes' );
46+
47+
$detached_subscriptions_ids = [];
48+
foreach ( $post_ids as $post_id ) {
49+
$subscription = wcs_get_subscription( $post_id );
50+
51+
if ( ! $subscription instanceof WC_Subscription ) {
52+
continue;
53+
}
54+
55+
if ( WC_Stripe_Subscriptions_Helper::is_subscription_payment_method_detached( $subscription ) ) {
56+
$detached_subscriptions_ids[] = $subscription->get_id();
57+
}
58+
}
59+
return add_query_arg(
60+
'detached-subscriptions',
61+
implode( ',', $detached_subscriptions_ids ),
62+
$redirect_url
63+
);
64+
}
65+
return $redirect_url;
66+
}
67+
}

includes/class-wc-stripe.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ public function init() {
115115
if ( is_admin() ) {
116116
require_once WC_STRIPE_PLUGIN_PATH . '/includes/admin/class-wc-stripe-privacy.php';
117117
}
118+
118119
if ( file_exists( WC_STRIPE_PLUGIN_PATH . '/includes/class-wc-stripe-feature-flags.php' ) ) {
119120
require_once WC_STRIPE_PLUGIN_PATH . '/includes/class-wc-stripe-feature-flags.php';
120121
}
@@ -243,6 +244,11 @@ public function init() {
243244
require_once WC_STRIPE_PLUGIN_PATH . '/includes/admin/class-wc-stripe-payment-gateways-controller.php';
244245
new WC_Stripe_Payment_Gateways_Controller();
245246
}
247+
248+
if ( WC_Stripe_Subscriptions_Helper::is_subscriptions_enabled() ) {
249+
require_once WC_STRIPE_PLUGIN_PATH . '/includes/admin/class-wc-stripe-subscription-detached-bulk-action.php';
250+
new WC_Stripe_Subscription_Detached_Bulk_Action();
251+
}
246252
}
247253

248254
// REMOVE IN THE FUTURE.

includes/compat/class-wc-stripe-subscriptions-helper.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,7 @@ public static function get_detached_subscriptions( $limit = -1 ) {
130130
}
131131

132132
if ( self::is_subscription_payment_method_detached( $subscription ) ) {
133-
$detached_subscriptions[] = [
134-
'id' => $subscription->get_id(),
135-
'customer_id' => $subscription->get_meta( '_stripe_customer_id' ),
136-
'change_payment_method_url' => $subscription->get_change_payment_method_url(),
137-
];
133+
$detached_subscriptions[] = self::get_detached_payment_data_from_subscription( $subscription );
138134
}
139135
}
140136

@@ -215,6 +211,20 @@ public static function is_manual_renewal_enabled() {
215211
return false;
216212
}
217213

214+
/**
215+
* Extracts data from a subscription object for detached subscriptions.
216+
*
217+
* @param WC_Subscription $subscription The subscription object to extract data from.
218+
* @return array
219+
*/
220+
public static function get_detached_payment_data_from_subscription( $subscription ) {
221+
return [
222+
'id' => $subscription->get_id(),
223+
'customer_id' => $subscription->get_meta( '_stripe_customer_id' ),
224+
'change_payment_method_url' => $subscription->get_change_payment_method_url(),
225+
];
226+
}
227+
218228
/**
219229
* Builds a string containing messages about subscriptions that are detached from the customer.
220230
*

readme.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o
111111
== Changelog ==
112112

113113
= 9.8.0 - xxxx-xx-xx =
114+
* Add - Adds a new bulk action option to the subscriptions listing screen to check for detached payment methods
114115
* Dev - Use product type constants that were added in WooCommerce 9.7
115116
* Dev - Removes the inclusion of the deprecated WC_Stripe_Order class
116117
* Add - Introduces a new banner to promote the Optimized Checkout feature in the Stripe settings page for versions 9.8 and above

tests/phpunit/Admin/WC_Stripe_Admin_Notices_Test.php

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -539,16 +539,16 @@ public function options_to_notices_map() {
539539
],
540540
[
541541
[
542-
'woocommerce_stripe_settings' => [
542+
'woocommerce_stripe_settings' => [
543543
'enabled' => 'yes',
544544
'testmode' => 'no',
545545
'publishable_key' => 'pk_live_valid_test_key',
546546
'secret_key' => 'sk_live_valid_test_key',
547547
'upe_checkout_experience_accepted_payments' => [ 'card', 'eps' ],
548548
],
549-
'wc_stripe_show_style_notice' => 'no',
550-
'home' => 'https://...',
551-
'wc_stripe_show_sca_notice' => 'no',
549+
'wc_stripe_show_style_notice' => 'no',
550+
'home' => 'https://...',
551+
'wc_stripe_show_sca_notice' => 'no',
552552
],
553553
[
554554
'upe_payment_methods',
@@ -622,6 +622,7 @@ function ( $id ) use ( $value ) {
622622
foreach ( $post_globals as $key => $value ) {
623623
unset( $GLOBALS[ $key ] );
624624
}
625+
WC_Subscriptions::$wcs_get_subscription = null;
625626
}
626627

627628
$theorder = $original_order;
@@ -675,4 +676,77 @@ public function provide_test_subscription_check_detachment() {
675676
],
676677
];
677678
}
679+
680+
/**
681+
* Tests for `subscription_check_detachment_bulk_action`.
682+
*
683+
* @param array|null $request_params Request parameters to simulate.
684+
* @param int $expected_count Expected number of notices.
685+
* @param string $expected_content Expected content in the notice message.
686+
* @return void
687+
*
688+
* @dataProvider provide_test_subscription_check_detachment_bulk_action
689+
*/
690+
public function test_subscription_check_detachment_bulk_action( $request_params, $subscriptions, $expected_count, $expected_content ) {
691+
if ( $request_params ) {
692+
$_REQUEST = $request_params;
693+
}
694+
695+
if ( count( $subscriptions ) > 0 ) {
696+
WC_Subscriptions::set_wcs_get_subscription(
697+
function ( $id ) use ( $subscriptions ) {
698+
return $subscriptions[0];
699+
}
700+
);
701+
}
702+
703+
$notices = new WC_Stripe_Admin_Notices();
704+
$notices->subscription_check_detachment_bulk_action();
705+
706+
$actual = $notices->notices;
707+
708+
// Clean up.
709+
unset( $_REQUEST );
710+
WC_Subscriptions::$wcs_get_subscription = null;
711+
712+
$this->assertCount( $expected_count, $actual );
713+
714+
if ( $expected_content ) {
715+
$this->assertArrayHasKey( 'subscription_detached_bulk_action', $actual );
716+
$this->assertStringContainsString( $expected_content, $actual['subscription_detached_bulk_action']['message'] );
717+
} else {
718+
$this->assertArrayNotHasKey( 'subscription_detached_bulk_action', $actual );
719+
}
720+
}
721+
722+
/**
723+
* Data provider for `test_subscription_check_detachment_bulk_action`.
724+
*
725+
* @return array
726+
*/
727+
public function provide_test_subscription_check_detachment_bulk_action() {
728+
$subscription = new WC_Subscription();
729+
$subscription->save();
730+
731+
return [
732+
'detached subscription IDs, but not actual subscriptions' => [
733+
'request params' => [ 'detached-subscriptions' => '123' ],
734+
'subscriptions' => [],
735+
'expected count' => 1,
736+
'expected content' => 'No detached subscriptions found.',
737+
],
738+
'detached subscription IDs, with actual subscriptions' => [
739+
'request params' => [ 'detached-subscriptions' => '123' ],
740+
'subscriptions' => [ $subscription ],
741+
'expected count' => 1,
742+
'expected content' => 'Below are the affected subscriptions and their update links:',
743+
],
744+
'no detached subscriptions' => [
745+
'request params' => null,
746+
'subscriptions' => [],
747+
'expected count' => 0,
748+
'expected content' => '',
749+
],
750+
];
751+
}
678752
}

0 commit comments

Comments
 (0)