Skip to content

Commit a08dd79

Browse files
committed
fix(reactivation): address remaining CodeRabbit findings from PR #751 review
- renew(): capture $previous_status before set_status() so the date_cancellation guard compares against the pre-update status. Previously the check was always false because get_status() returned the new 'active' value after set_status() ran. - reactivate(): remove ': bool' return type (renew() can return WP_Error); update PHPDoc to 'bool|\WP_Error'; change success check from 'if ($result)' to 'if (true === $result)' so WP_Error objects (truthy) don't trigger the post-reactivation hooks. - build_from_membership() reactivation path: set duration/duration_unit from the plan BEFORE calling add_product() so line items are created with the correct billing period. Replace get_addon_ids() (discards quantities) with get_addon_products() (product_id => quantity map) so addon quantities are preserved when rebuilding the cart. Closes #752
1 parent dad36a4 commit a08dd79

File tree

2 files changed

+47
-27
lines changed

2 files changed

+47
-27
lines changed

inc/checkout/class-cart.php

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -882,37 +882,46 @@ protected function build_from_membership($membership_id): bool {
882882
*/
883883
$plan_id = $membership->get_plan_id();
884884

885-
if ($plan_id) {
886-
$this->attributes->products = [$plan_id];
887-
888-
$addon_ids = $membership->get_addon_ids();
889-
890-
if (! empty($addon_ids)) {
891-
$this->attributes->products = array_merge($this->attributes->products, $addon_ids);
892-
}
893-
}
894-
895-
// Set up country and currency, then add products and return
885+
// Set up country and currency before building products
896886
$this->country = $this->country ?: $this->customer->get_country();
897887

898888
$this->set_currency($membership->get_currency());
899889

900-
if (empty($this->attributes->products)) {
890+
/*
891+
* Set duration from the plan BEFORE calling add_product() so that
892+
* line items are created with the correct billing period. Previously
893+
* this was set after add_product(), meaning products were added with
894+
* the default/empty duration and the correct values were never used.
895+
*
896+
* @since 2.5.0
897+
*/
898+
$plan_product = $membership->get_plan();
899+
900+
if ($plan_product && ! $membership->is_free()) {
901+
$this->duration = $plan_product->get_duration();
902+
$this->duration_unit = $plan_product->get_duration_unit();
903+
}
904+
905+
if (! $plan_id) {
901906
$this->errors->add('no_plan', __('This membership has no plan to reactivate.', 'ultimate-multisite'));
902907

903908
return true;
904909
}
905910

906-
foreach ($this->attributes->products as $product_id) {
907-
$this->add_product($product_id);
908-
}
911+
/*
912+
* Rebuild the product list from the membership, preserving addon
913+
* quantities. get_addon_ids() discards quantities; get_addon_products()
914+
* returns the full product_id => quantity map so each addon is added
915+
* with the correct quantity.
916+
*
917+
* @since 2.5.0
918+
*/
919+
$this->add_product($plan_id);
909920

910-
// Set duration from the plan
911-
$plan_product = $membership->get_plan();
921+
$addon_products = $membership->get_addon_products();
912922

913-
if ($plan_product && ! $membership->is_free()) {
914-
$this->duration = $plan_product->get_duration();
915-
$this->duration_unit = $plan_product->get_duration_unit();
923+
foreach ($addon_products as $addon_id => $quantity) {
924+
$this->add_product((int) $addon_id, (int) $quantity);
916925
}
917926

918927
return true;

inc/models/class-membership.php

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2304,6 +2304,16 @@ public function renew($auto_renew = false, $status = 'active', $expiration = '')
23042304
*/
23052305
do_action('wu_membership_pre_renew', $expiration, $this->get_id(), $this);
23062306

2307+
/*
2308+
* Capture the current status BEFORE calling set_status() so the
2309+
* cancellation-clear guard below can compare against the previous
2310+
* state. After set_status() runs, get_status() returns the new value
2311+
* and the CANCELLED check would never be true.
2312+
*
2313+
* @since 2.5.0
2314+
*/
2315+
$previous_status = $this->get_status();
2316+
23072317
$this->set_date_expiration($expiration);
23082318

23092319
if ( ! empty($status)) {
@@ -2312,13 +2322,14 @@ public function renew($auto_renew = false, $status = 'active', $expiration = '')
23122322

23132323
/*
23142324
* Clear the cancellation date only when reactivating a previously
2315-
* cancelled membership. Checks the current status (before the update)
2316-
* to avoid clearing historical cancellation data on regular recurring
2317-
* renewals where the membership was never in a cancelled state.
2325+
* cancelled membership. Uses $previous_status (captured before the
2326+
* set_status() call above) to avoid clearing historical cancellation
2327+
* data on regular recurring renewals where the membership was never
2328+
* in a cancelled state.
23182329
*
23192330
* @since 2.5.0
23202331
*/
2321-
if ('active' === $status && Membership_Status::CANCELLED === $this->get_status() && ! empty($this->get_date_cancellation())) {
2332+
if (Membership_Status::ACTIVE === $status && Membership_Status::CANCELLED === $previous_status && ! empty($this->get_date_cancellation())) {
23222333
$this->set_date_cancellation(null);
23232334
}
23242335

@@ -2363,9 +2374,9 @@ public function renew($auto_renew = false, $status = 'active', $expiration = '')
23632374
*
23642375
* @param bool $auto_renew Whether to auto-renew.
23652376
* @param string $expiration Optional expiration date in MySQL format.
2366-
* @return bool Whether the reactivation was successful.
2377+
* @return bool|\WP_Error True on success, WP_Error if renew()/save() fails.
23672378
*/
2368-
public function reactivate($auto_renew = false, $expiration = ''): bool {
2379+
public function reactivate($auto_renew = false, $expiration = '') {
23692380

23702381
$id = $this->get_id();
23712382

@@ -2394,7 +2405,7 @@ public function reactivate($auto_renew = false, $expiration = ''): bool {
23942405

23952406
$result = $this->renew($auto_renew, 'active', $expiration);
23962407

2397-
if ($result) {
2408+
if (true === $result) {
23982409
wu_log_add("membership-{$id}", sprintf('Membership #%d reactivated successfully. Old cancel date: %s', $id, $old_cancel_date ?: 'none'));
23992410

24002411
/**

0 commit comments

Comments
 (0)