Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding admin notices for detached subscriptions #3863

Merged
merged 9 commits into from
Feb 11, 2025
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*** Changelog ***

= 9.2.0 - xxxx-xx-xx =
* Add - Adds a new notice for store admins when there are subscriptions without a payment method attached.
* Fix - Hides "pay" and "cancel" buttons on the order received page when an Amazon Pay order is pending, since it may take a while to be confirmed.
* Dev - Replaces part of the StoreAPI call code for the cart endpoints to use the newly introduced filter.
* Fix - Switch booking products back to using non-StoreAPI add-to-cart methods.
Expand Down
104 changes: 102 additions & 2 deletions includes/admin/class-wc-stripe-admin-notices.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@
* @since 4.1.0
*/
class WC_Stripe_Admin_Notices {
/**
* Transient key for detached subscriptions.
*
* @var string
*/
private const DETACHED_SUBSCRIPTIONS_TRANSIENT_KEY = 'wcstripe_detached_subscriptions';

/**
* Stripe customer page base URL.
*
* @var string
*/
private const STRIPE_CUSTOMER_PAGE_BASE_URL = 'https://dashboard.stripe.com/customers/';

/**
* Notices (array)
*
Expand Down Expand Up @@ -58,6 +72,11 @@ public function admin_notices() {
// All other payment methods.
$this->payment_methods_check_environment();

// Subscription related checks.
if ( class_exists( 'WC_Subscriptions' ) && class_exists( 'WC_Subscription' ) && version_compare( WC_Subscriptions::$version, '2.2.0', '>=' ) ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have moved a helper method with this check here so we can use it in non-gateway classes.

$this->subscriptions_check_environment();
}

foreach ( (array) $this->notices as $notice_key => $notice ) {
echo '<div class="' . esc_attr( $notice['class'] ) . '" style="position:relative;">';

Expand Down Expand Up @@ -379,6 +398,45 @@ public function payment_methods_check_environment() {
}
}

/**
* Environment check for subscriptions.
*
* @return void
*/
public function subscriptions_check_environment() {
$detached_messages = '';
$subscriptions = $this->get_detached_subscriptions();
foreach ( $subscriptions as $subscription ) {
$customer_payment_method_link = sprintf(
'<a href="%s">%s</a>',
esc_url( $subscription['change_payment_method_url'] ),
esc_html(
/* translators: this is a text for a link pointing to the customer's payment method page */
__( 'this link &rarr;', 'woocommerce-gateway-stripe' )
)
);
$customer_stripe_page = sprintf(
'<a href="%s">%s</a>',
esc_url( self::STRIPE_CUSTOMER_PAGE_BASE_URL . $subscription['customer_id'] ),
esc_html(
/* translators: this is a text for a link pointing to the customer's page on Stripe */
__( 'here &rarr;', 'woocommerce-gateway-stripe' )
)
);
$detached_messages .= sprintf(
/* translators: %1$s is the subscription ID. %2$s is a customer payment method page. %3$s is the customer's page on Stripe */
__( 'Subscription #%1$s\'s payment method is missing, <strong>preventing renewals</strong>. Share %2$s with the customer to update it or manually set the <strong>Stripe Payment Method ID</strong> meta field in the subscriptions details "Billing" section to another from %3$s.', 'woocommerce-gateway-stripe' ),
$subscription['id'],
$customer_payment_method_link,
$customer_stripe_page
);
}
$show_notice = get_option( 'wc_stripe_show_subscriptions_notice' );
if ( ! empty( $detached_messages ) && 'no' !== $show_notice ) {
$this->add_admin_notice( 'subscriptions', 'notice notice-error', $detached_messages, true );
}
}

/**
* Hides any admin notices.
*
Expand Down Expand Up @@ -421,8 +479,6 @@ public function hide_notices() {
break;
case 'sofort':
update_option( 'wc_stripe_show_sofort_notice', 'no' );
break;
case 'sofort':
update_option( 'wc_stripe_show_sofort_upe_notice', 'no' );
break;
case 'sca':
Expand All @@ -437,6 +493,9 @@ public function hide_notices() {
case 'upe_payment_methods':
update_option( 'wc_stripe_show_upe_payment_methods_notice', 'no' );
break;
case 'subscriptions':
update_option( 'wc_stripe_show_subscriptions_notice', 'no' );
break;
}
}
}
Expand Down Expand Up @@ -470,6 +529,47 @@ public function stripe_updated() {
update_option( 'wc_stripe_show_sca_notice', 'no' );
}
}

/**
* Returns a list of subscriptions without a payment method attached.
*
* @return array
*/
private function get_detached_subscriptions() {
// Check if we have a cached result.
$cached_subscriptions = get_transient( self::DETACHED_SUBSCRIPTIONS_TRANSIENT_KEY );
if ( ! empty( $cached_subscriptions ) ) {
return $cached_subscriptions;
}

$detached_subscriptions = [];
$subscriptions = wcs_get_subscriptions(
[
'subscriptions_per_page' => -1,
'orderby' => 'date',
'order' => 'DESC',
'subscription_status' => [ 'active', 'on-hold', 'pending-cancel' ],
]
);
foreach ( $subscriptions as $subscription ) {
$source_id = $subscription->get_meta( '_stripe_source_id' );
if ( $source_id ) {
$payment_method = WC_Stripe_API::get_payment_method( $source_id );
if ( ! $payment_method->customer ) {
$detached_subscriptions[] = [
'id' => $subscription->get_id(),
'customer_id' => $subscription->get_meta( '_stripe_customer_id' ),
'change_payment_method_url' => $subscription->get_change_payment_method_url(),
];
}
}
}

// Cache the result for a day.
set_transient( self::DETACHED_SUBSCRIPTIONS_TRANSIENT_KEY, $detached_subscriptions, DAY_IN_SECONDS );

return $detached_subscriptions;
}
}

new WC_Stripe_Admin_Notices();
1 change: 1 addition & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o
== Changelog ==

= 9.2.0 - xxxx-xx-xx =
* Add - Adds a new notice for store admins when there are subscriptions without a payment method attached.
* Fix - Hides "pay" and "cancel" buttons on the order received page when an Amazon Pay order is pending, since it may take a while to be confirmed.
* Dev - Replaces part of the StoreAPI call code for the cart endpoints to use the newly introduced filter.
* Fix - Switch booking products back to using non-StoreAPI add-to-cart methods.
Expand Down
20 changes: 20 additions & 0 deletions tests/phpunit/helpers/class-wc-subscriptions-helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ function wcs_get_subscriptions_for_order( $order ) {
return (array) WC_Subscriptions_Helpers::$wcs_get_subscriptions_for_order;
}

/**
* A function to mock wcs_get_subscriptions.
*
* @return array
*/
function wcs_get_subscriptions() {
if ( ! WC_Subscriptions_Helpers::$wcs_get_subscriptions ) {
return [];
}

return (array) WC_Subscriptions_Helpers::$wcs_get_subscriptions;
}

/**
* A helper class for setting up mocks for WC_Subscriptions functions.
*/
Expand All @@ -28,4 +41,11 @@ class WC_Subscriptions_Helpers {
* @var array
*/
public static $wcs_get_subscriptions_for_order = null;

/**
* Mock for wcs_get_subscriptions.
*
* @var array
*/
public static $wcs_get_subscriptions = null;
}
Loading