From d53ad99d16f883c124a38d37ad3766b0b640cf94 Mon Sep 17 00:00:00 2001 From: David Stone Date: Tue, 9 Sep 2025 23:03:23 -0600 Subject: [PATCH 1/5] Only add credit if it's a paid recurring plan --- inc/checkout/class-cart.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/inc/checkout/class-cart.php b/inc/checkout/class-cart.php index c327976b5..bac373627 100644 --- a/inc/checkout/class-cart.php +++ b/inc/checkout/class-cart.php @@ -1086,8 +1086,9 @@ protected function build_from_membership($membership_id): bool { if (($is_same_product && $membership->get_amount() > $this->get_recurring_total()) || (! $is_same_product && $old_price_per_day > $new_price_per_day)) { $this->cart_type = 'downgrade'; - // If membership is active or trialing we will schendule the swap - if ($membership->is_active() || $membership->get_status() === Membership_Status::TRIALING) { + // If membership is active, schedule the swap and apply credit + // For trialing memberships, only schedule the swap without credit since they haven't been charged yet + if ($membership->is_active()) { $line_item_params = apply_filters( 'wu_checkout_credit_line_item_params', [ @@ -1195,7 +1196,7 @@ protected function calculate_prorate_credits() { */ /* - * If the membership is in trial period theres nothing to prorate. + * If the membership is in trial period there's nothing to prorate. */ if ($this->membership->get_status() === Membership_Status::TRIALING) { return; From c9bdf3c4ea6570765b51abcd384181cc4041824a Mon Sep 17 00:00:00 2001 From: David Stone Date: Tue, 9 Sep 2025 23:04:15 -0600 Subject: [PATCH 2/5] fix: only consider main domains as custom domains --- .../class-limit-domain-mapping.php | 9 +++- inc/managers/class-domain-manager.php | 52 +++++++++++-------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/inc/limitations/class-limit-domain-mapping.php b/inc/limitations/class-limit-domain-mapping.php index 0957c2d93..e9a3cc354 100644 --- a/inc/limitations/class-limit-domain-mapping.php +++ b/inc/limitations/class-limit-domain-mapping.php @@ -10,6 +10,8 @@ namespace WP_Ultimo\Limitations; // Exit if accessed directly +use WP_Ultimo\Managers\Domain_Manager; + defined('ABSPATH') || exit; /** @@ -167,7 +169,12 @@ public function get_current_domain_count($site_id = null) { $active_count = 0; foreach ($domains as $domain) { - if ($domain->is_active()) { + $domain_url = $domain->get_domain(); + if (str_starts_with($domain_url, 'www.')) { + $domain_url = substr($domain_url, 4); + } + + if (Domain_Manager::is_main_domain($domain_url) && $domain->is_active()) { ++$active_count; } } diff --git a/inc/managers/class-domain-manager.php b/inc/managers/class-domain-manager.php index 5fa99498d..ee17e4f9e 100644 --- a/inc/managers/class-domain-manager.php +++ b/inc/managers/class-domain-manager.php @@ -54,6 +54,36 @@ class Domain_Manager extends Base_Manager { */ protected $integrations = []; + /** + * Checks if this is a main domain or a subdomain. + * + * @param string $domain the domain. + * + * @return bool + */ + public static function is_main_domain(string $domain) { + // Check if this is a main domain (no subdomain parts) + // A main domain has only 2 parts when split by dots (e.g., example.com) + // or 3 parts if it's a known TLD structure (e.g., example.co.uk) + $parts = explode('.', $domain); + + // Simple heuristic: if domain has only 2 parts, it's definitely a main domain + if (count($parts) <= 2) { + return true; // e.g., example.com + } + + // For 3+ parts, check if it's a main domain with multi-part TLD + $known_multi_part_tlds = apply_filters('wu_multi_part_tlds', ['.co.uk', '.com.au', '.co.nz', '.com.br', '.co.in']); + $last_two_parts = '.' . $parts[ count($parts) - 2 ] . '.' . $parts[ count($parts) - 1 ]; + + // If it has exactly 3 parts and matches a known multi-part TLD, it's a main domain + if (count($parts) === 3 && in_array($last_two_parts, $known_multi_part_tlds, true)) { + return true; // e.g., example.co.uk + } + // Must be a subdomain. + return false; + } + /** * Returns the list of available host integrations. * @@ -441,27 +471,7 @@ public function should_create_www_subdomain($domain) { return false; case 'main_only': - // Check if this is a main domain (no subdomain parts) - // A main domain has only 2 parts when split by dots (e.g., example.com) - // or 3 parts if it's a known TLD structure (e.g., example.co.uk) - $parts = explode('.', $domain); - - // Simple heuristic: if domain has only 2 parts, it's definitely a main domain - if (count($parts) <= 2) { - return true; // e.g., example.com - } - - // For 3+ parts, check if it's a main domain with multi-part TLD - $known_multi_part_tlds = apply_filters('wu_multi_part_tlds', ['.co.uk', '.com.au', '.co.nz', '.com.br', '.co.in']); - $last_two_parts = '.' . $parts[ count($parts) - 2 ] . '.' . $parts[ count($parts) - 1 ]; - - // If it has exactly 3 parts and matches a known multi-part TLD, it's a main domain - if (count($parts) === 3 && in_array($last_two_parts, $known_multi_part_tlds, true)) { - return true; // e.g., example.co.uk - } - - // Otherwise, it's a subdomain - return false; + return self::is_main_domain($domain); case 'always': default: From 3d0a9d5a57c8ce50650118d1629c866970934220 Mon Sep 17 00:00:00 2001 From: David Stone Date: Tue, 9 Sep 2025 23:04:37 -0600 Subject: [PATCH 3/5] fix: cart test --- tests/WP_Ultimo/Checkout/Cart_Test.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/WP_Ultimo/Checkout/Cart_Test.php b/tests/WP_Ultimo/Checkout/Cart_Test.php index aa18f0076..0d4ce323d 100644 --- a/tests/WP_Ultimo/Checkout/Cart_Test.php +++ b/tests/WP_Ultimo/Checkout/Cart_Test.php @@ -275,7 +275,7 @@ public function test_domain_mapping_downgrade_validation_over_limit() { $domain1 = wu_create_domain( [ 'blog_id' => $site->get_id(), - 'domain' => 'custom1.example.com', + 'domain' => 'www.example.com', 'active' => true, 'primary_domain' => true, 'stage' => 'done', @@ -285,7 +285,7 @@ public function test_domain_mapping_downgrade_validation_over_limit() { $domain2 = wu_create_domain( [ 'blog_id' => $site->get_id(), - 'domain' => 'custom2.example.com', + 'domain' => 'www.example.co.uk', 'active' => true, 'primary_domain' => false, 'stage' => 'done', @@ -295,7 +295,7 @@ public function test_domain_mapping_downgrade_validation_over_limit() { $domain3 = wu_create_domain( [ 'blog_id' => $site->get_id(), - 'domain' => 'custom3.example.com', + 'domain' => 'example.co', 'active' => true, 'primary_domain' => false, 'stage' => 'done', @@ -534,7 +534,7 @@ public function test_domain_mapping_downgrade_validation_disabled_in_new_plan() $site = wu_create_site( [ 'title' => 'Test Site for Domain Validation 3', - 'domain' => 'domain-test-3.example.com', + 'domain' => 'sub.example.ro', 'template_id' => 1, ] ); @@ -561,7 +561,7 @@ public function test_domain_mapping_downgrade_validation_disabled_in_new_plan() $domain1 = wu_create_domain( [ 'blog_id' => $site->get_id(), - 'domain' => 'custom-disabled.example.com', + 'domain' => 'example.eu', 'active' => true, 'primary_domain' => true, 'stage' => 'done', From b44d2ba1932dc57ca80c1116290195091e49d1b7 Mon Sep 17 00:00:00 2001 From: David Stone Date: Sun, 14 Sep 2025 21:27:34 -0600 Subject: [PATCH 4/5] revert change for downgrade of trials --- inc/checkout/class-cart.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/inc/checkout/class-cart.php b/inc/checkout/class-cart.php index bac373627..066538fc1 100644 --- a/inc/checkout/class-cart.php +++ b/inc/checkout/class-cart.php @@ -1086,9 +1086,8 @@ protected function build_from_membership($membership_id): bool { if (($is_same_product && $membership->get_amount() > $this->get_recurring_total()) || (! $is_same_product && $old_price_per_day > $new_price_per_day)) { $this->cart_type = 'downgrade'; - // If membership is active, schedule the swap and apply credit - // For trialing memberships, only schedule the swap without credit since they haven't been charged yet - if ($membership->is_active()) { + // If membership is active or trialing we will schendule the swap + if ($membership->is_active() || $membership->get_status() === Membership_Status::TRIALING) { $line_item_params = apply_filters( 'wu_checkout_credit_line_item_params', [ From de7e969c39134e7fc0110d126b3f99109c21be6e Mon Sep 17 00:00:00 2001 From: David Stone Date: Sun, 21 Sep 2025 17:12:54 -0600 Subject: [PATCH 5/5] Update inc/managers/class-domain-manager.php Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- inc/managers/class-domain-manager.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inc/managers/class-domain-manager.php b/inc/managers/class-domain-manager.php index ee17e4f9e..5857dc8ad 100644 --- a/inc/managers/class-domain-manager.php +++ b/inc/managers/class-domain-manager.php @@ -62,6 +62,8 @@ class Domain_Manager extends Base_Manager { * @return bool */ public static function is_main_domain(string $domain) { + // Normalize: lowercase, trim spaces, drop trailing dot + $domain = strtolower(trim(rtrim($domain, '.'))); // Check if this is a main domain (no subdomain parts) // A main domain has only 2 parts when split by dots (e.g., example.com) // or 3 parts if it's a known TLD structure (e.g., example.co.uk)