Skip to content

Commit

Permalink
feat(wcs): add expired subscription cli tool (#3593)
Browse files Browse the repository at this point in the history
This PR adds a cli command to migrate the status of all on-hold subscriptions that have failed all retries to expired
  • Loading branch information
chickenn00dle authored Dec 9, 2024
1 parent f42a75b commit 5d39398
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 0 deletions.
2 changes: 2 additions & 0 deletions includes/cli/class-initializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public static function init() {
include_once NEWSPACK_ABSPATH . 'includes/cli/class-ras.php';
include_once NEWSPACK_ABSPATH . 'includes/cli/class-ras-esp-sync.php';
include_once NEWSPACK_ABSPATH . 'includes/cli/class-co-authors-plus.php';
include_once NEWSPACK_ABSPATH . 'includes/cli/class-woocommerce-subscriptions.php';
}

/**
Expand Down Expand Up @@ -66,5 +67,6 @@ public static function register_comands() {
'schedule_author_term_backfill',
]
);
WP_CLI::add_command( 'newspack migrate-expired-subscriptions', [ 'Newspack\CLI\WooCommerce_Subscriptions', 'migrate_expired_subscriptions' ] );
}
}
184 changes: 184 additions & 0 deletions includes/cli/class-woocommerce-subscriptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<?php
/**
* WooCommerce Subscriptions Integration CLI commands.
*
* @package Newspack
*/

namespace Newspack\CLI;

use WP_CLI;
use Newspack\Woocommerce_Subscriptions as WooCommerce_Subscriptions_Integration;

defined( 'ABSPATH' ) || exit;

/**
* WooCommerce Subscriptions Integration CLI commands.
*/
class WooCommerce_Subscriptions {
/**
* Flag for live mode.
*
* @var bool
*/
private static $live = false;

/**
* Flag for verbose output.
*
* @var bool
*/
private static $verbose = false;

/**
* Subscription ids to process.
*
* @var bool|array
*/
private static $ids = false;

/**
* Migrate status of on-hold WooCommerce subscriptions that have failed all payment retries to expired.
*
* ## OPTIONS
*
* [--live]
* : Run the command in live mode, updating the subscriptions.
*
* [--verbose]
* : Produce more output.
*
* [--ids]
* : Comma-separated list of subscription IDs. If provided, only ubscriptions with these IDs will be processed.
*
* @param array $args Positional arguments.
* @param array $assoc_args Assoc arguments.
*
* @return void
*/
public function migrate_expired_subscriptions( $args, $assoc_args ) {
WP_CLI::line( '' );
if ( ! WooCommerce_Subscriptions_Integration::is_enabled() ) {
WP_CLI::error( 'WooCommerce Subscriptions Integration is not enabled.' );
WP_CLI::line( '' );
return;
}
self::$ids = isset( $assoc_args['ids'] ) ? explode( ',', $assoc_args['ids'] ) : false;
self::$live = isset( $assoc_args['live'] ) ? true : false;
self::$verbose = isset( $assoc_args['verbose'] ) ? true : false;
$updated = 0;
$page = 1;
$per_page = 25;
$subscriptions = self::get_subscriptions( $page );
if ( empty( $subscriptions ) ) {
WP_CLI::success( 'No on-hold subscriptions to process.' );
WP_CLI::line( '' );
return;
}
WP_CLI::line( 'Processing subscriptions in ' . ( self::$live ? 'live' : 'dry run' ) . ' mode...' );
WP_CLI::line( '' );
while ( ! empty( $subscriptions ) ) {
foreach ( $subscriptions as $subscription ) {
$id = $subscription->get_id();
if ( self::$verbose ) {
WP_CLI::line( 'Processing subscription ' . $id . '...' );
}
// A pending retry indicates the subscription is awaiting payment retry.
if ( $subscription->get_date( 'payment_retry' ) > 0 ) {
if ( self::$verbose ) {
WP_CLI::line( 'Subscription is awaiting payment retry. Moving to next subscription...' );
WP_CLI::line( '' );
}
continue;
}
$renewal_order = $subscription->get_last_order(
'all',
[ 'renewal' ],
[
'completed',
'processing',
'refunded',
]
);
// No failed or pending renewal orders indicates the subscription was likely manually placed on hold.
if ( empty( $renewal_order ) ) {
if ( self::$verbose ) {
WP_CLI::line( 'Subscription has no pending renewal orders. Moving to next subscription...' );
WP_CLI::line( '' );
}
continue;
}
$last_retry = \WCS_Retry_Manager::store()->get_last_retry_for_order( wcs_get_objects_property( $renewal_order, 'id' ) );
// No retries indicates the subscription was likely manually placed on hold.
if ( empty( $last_retry ) ) {
if ( self::$verbose ) {
WP_CLI::line( 'No retries scheduled. Moving to next subscription...' );
WP_CLI::line( '' );
}
continue;
}
// A non failed status indicates the retry was either manually cancelled
// or was successful at one point but likely placed on hold for some other reason.
if ( 'failed' !== $last_retry->get_status() ) {
if ( self::$verbose ) {
WP_CLI::line( 'Last retry does not have a failed status. Moving to next subscription...' );
WP_CLI::line( '' );
}
continue;
} else {
if ( self::$verbose ) {
WP_CLI::line( 'Updating subscription status to expired...' );
}
if ( self::$live ) {
$subscription->update_status( 'expired', __( 'Subscription status updated by Newspack CLI command.', 'newspack-plugin' ) );
$subscription->set_end_date( $last_retry->get_date() );
$subscription->save();
}
++$updated;
}
if ( self::$verbose ) {
WP_CLI::line( 'Finished processing subscription ' . $id );
WP_CLI::line( '' );
}
}
$subscriptions = self::get_subscriptions( ++$page );
}
WP_CLI::success( 'Finished processing subscriptions. ' . $updated . ' subscriptions updated.' );
if ( ! self::$live ) {
WP_CLI::warning( 'Dry run. Use --live flag to process live subscriptions.' );
}
WP_CLI::line( '' );
}

/**
* Get subscriptions to process.
*
* @param int $page Page number.
*
* @return array
*/
private static function get_subscriptions( $page = 1 ) {
$subscriptions = [];
if ( false !== self::$ids ) {
while ( ! empty( self::$ids ) ) {
$id = array_shift( self::$ids );
if ( ! is_numeric( $id ) ) {
continue;
}
$subscription = wcs_get_subscription( $id );
if ( $subscription ) {
$subscriptions[] = $subscription;
}
}
} else {
$subscriptions = wcs_get_subscriptions(
[
'paged' => $page,
'subscriptions_per_page' => 25,
'subscription_status' => 'on-hold',
]
);
}
return $subscriptions;
}
}

0 comments on commit 5d39398

Please sign in to comment.