Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion inc/admin-pages/class-settings-admin-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ public function default_view(): void {
'style' => '',
'data-on-load' => 'remove_block_ui',
'data-wu-app' => str_replace('-', '_', $section_slug),
'data-state' => wp_json_encode(wu_array_map_keys('wu_replace_dashes', Settings::get_instance()->get_all(true))),
'data-state' => wp_json_encode(wu_array_map_keys('wu_replace_dashes', Settings::get_instance()->get_all_with_defaults(true))),
],
]
);
Expand Down
22 changes: 18 additions & 4 deletions inc/checkout/class-checkout.php
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ public function process_order() {
/*
* Checks for free memberships.
*/
if ($this->order->is_free() && $this->order->get_recurring_total() === 0.0 && (! wu_get_setting('enable_email_verification', true) || $this->customer->get_email_verification() !== 'pending')) {
if ($this->order->is_free() && $this->order->get_recurring_total() === 0.0 && $this->customer->get_email_verification() !== 'pending') {
if ($this->order->get_plan_id() === $this->membership->get_plan_id()) {
$this->membership->set_status(Membership_Status::ACTIVE);

Expand All @@ -829,7 +829,7 @@ public function process_order() {
$this->membership->set_date_trial_end(gmdate('Y-m-d 23:59:59', $this->order->get_billing_start_date()));
$this->membership->set_date_expiration(gmdate('Y-m-d 23:59:59', $this->order->get_billing_start_date()));

if (wu_get_setting('allow_trial_without_payment_method') && (! wu_get_setting('enable_email_verification', true) || $this->customer->get_email_verification() !== 'pending')) {
if (wu_get_setting('allow_trial_without_payment_method') && $this->customer->get_email_verification() !== 'pending') {
/*
* In this particular case, we need to set the status to trialing here as we will not update the membership after and then, publish the site.
*/
Expand Down Expand Up @@ -2259,9 +2259,23 @@ public function is_existing_user() {
*/
public function get_customer_email_verification_status() {

$should_confirm_email = wu_get_setting('enable_email_verification', true);
$email_verification_setting = wu_get_setting('enable_email_verification', 'free_only');

return $this->order->should_collect_payment() === false && $should_confirm_email ? 'pending' : 'none';
switch ($email_verification_setting) {
case 'never':
return 'none';

case 'always':
return 'pending';

case 'free_only':
return $this->order->should_collect_payment() === false ? 'pending' : 'none';

default:
// Legacy behavior - handle boolean values
$should_confirm_email = (bool) $email_verification_setting;
return $this->order->should_collect_payment() === false && $should_confirm_email ? 'pending' : 'none';
}
}

/**
Expand Down
38 changes: 34 additions & 4 deletions inc/class-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,21 @@ public function get_all($check_caps = false) {
return $this->settings;
}

public function get_all_with_defaults($check_caps = false) {
$all_settings = $this->get_all($check_caps);
foreach ($this->get_sections() as $section_slug => $section) {
foreach ($section['fields'] as $field_slug => $field_atts) {
if (is_callable($field_atts['value'])) {
$value = $field_atts['value']();
if (isset($all_settings[ $field_slug ]) && $value !== $all_settings[ $field_slug ]) {
$all_settings[ $field_slug ] = $value;
}
}
}
}
return $all_settings;
}

/**
* Get a specific settings from the plugin
*
Expand Down Expand Up @@ -724,10 +739,25 @@ public function default_sections(): void {
'login-and-registration',
'enable_email_verification',
[
'title' => __('Enable email verification', 'multisite-ultimate'),
'desc' => __('Enabling this option will require the customer to verify their email address when subscribing to a free plan or a plan with a trial period. Sites will not be created until the customer email verification status is changed to verified.', 'multisite-ultimate'),
'type' => 'toggle',
'default' => 1,
'title' => __('Email verification', 'multisite-ultimate'),
'desc' => __('Controls if email verification is required during registration. If set, sites will not be created until the customer email verification status is changed to verified.', 'multisite-ultimate'),
'type' => 'select',
'options' => [
'never' => __('Never require email verification', 'multisite-ultimate'),
'free_only' => __('Only for free plans', 'multisite-ultimate'),
'always' => __('Always require email verification', 'multisite-ultimate'),
],
'default' => 'free_only',
'value' => function () {
$raw = wu_get_setting('enable_email_verification', 'free_only');
if (1 === $raw || '1' === $raw || true === $raw) {
return 'free_only'; // legacy "enabled"
}
if (0 === $raw || '0' === $raw || false === $raw) {
return 'never'; // legacy "disabled"
}
return in_array($raw, ['never', 'free_only', 'always'], true) ? $raw : 'free_only';
},
]
);

Expand Down
2 changes: 1 addition & 1 deletion inc/models/class-membership.php
Original file line number Diff line number Diff line change
Expand Up @@ -2433,7 +2433,7 @@ public function save() {

// Set trial status if needed
if ($this->get_status() === Membership_Status::PENDING && $this->is_trialing() && ! $this->get_last_pending_payment()) {
if ( ! wu_get_setting('enable_email_verification', true) || $this->get_customer()->get_email_verification() !== 'pending') {
if ($this->get_customer()->get_email_verification() !== 'pending') {
$this->set_status(Membership_Status::TRIALING);
}
}
Comment on lines 2435 to 2439
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Null-guard customer before checking email verification; keep gating consistent with tri‑state logic

get_customer() can be falsy; dereferencing without a guard risks a fatal. Also, this check consults the raw email_verification property only. If the tri‑state is set to “never” (or “free_only” for paid plans), a customer might legitimately remain non‑verified yet should not block TRIALING. Consider centralizing the decision via a helper that derives the effective verification requirement/status, or at minimum guard null here.

Apply this minimal guard:

-      if ($this->get_customer()->get_email_verification() !== 'pending') {
-        $this->set_status(Membership_Status::TRIALING);
-      }
+      $customer = $this->get_customer();
+      if ($customer && $customer->get_email_verification() !== 'pending') {
+        $this->set_status(Membership_Status::TRIALING);
+      }

Follow‑up:

  • Verify that whatever computes the effective email‑verification status (per tri‑state and plan type) is invoked during signup so that email_verification is ‘pending’ only when required; otherwise this code may prematurely promote to TRIALING. If there’s a canonical helper (e.g., in Checkout), call it here instead of reading the raw property.

🏁 Script executed:

#!/bin/bash
# Locate get_customer() in the Membership model to inspect its return type and docblock
grep -R -nC3 "function get_customer" inc/models/class-membership.php

# Check where get_email_verification() is defined/used in the Membership class
grep -R -nC3 "get_email_verification" -n inc/models/class-membership.php

# Search for any centralized helper around email-verification logic
grep -R -nC3 "verification" inc/models

Length of output: 8337


🏁 Script executed:

#!/bin/bash
# Find definition of wu_get_customer to inspect its return behavior
grep -R "function wu_get_customer" -n .

# Find all references and where it's defined
grep -R "wu_get_customer(" -n .

Length of output: 3552


🏁 Script executed:

#!/bin/bash
# Print the wu_get_customer implementation to determine return behavior (can it return null/false?)
sed -n '1,80p' inc/functions/customer.php

Length of output: 1520


Guard get_customer() before get_email_verification() and centralize tri-state logic
Wrap get_customer() in a null/false check to prevent fatal errors and, when available, replace the raw get_email_verification() property check with a canonical helper for effective email-verification logic.

inc/models/class-membership.php
@@ -2436,3 +2436,6 @@ if ($this->get_status() === Membership_Status::PENDING && $this->is_trialing() && ! $this->get_last_pending_payment()) {
-   if ($this->get_customer()->get_email_verification() !== 'pending') {
-     $this->set_status(Membership_Status::TRIALING);
-   }
+   $customer = $this->get_customer();
+   if ($customer && $customer->get_email_verification() !== 'pending') {
+     $this->set_status(Membership_Status::TRIALING);
+   }
 }

Ensure the signup flow or a shared helper sets and evaluates email_verification per plan requirements so only required verifications block trial status.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ($this->get_status() === Membership_Status::PENDING && $this->is_trialing() && ! $this->get_last_pending_payment()) {
if ( ! wu_get_setting('enable_email_verification', true) || $this->get_customer()->get_email_verification() !== 'pending') {
if ($this->get_customer()->get_email_verification() !== 'pending') {
$this->set_status(Membership_Status::TRIALING);
}
}
if ( $this->get_status() === Membership_Status::PENDING
&& $this->is_trialing()
&& ! $this->get_last_pending_payment()
) {
$customer = $this->get_customer();
if ( $customer && $customer->get_email_verification() !== 'pending' ) {
$this->set_status( Membership_Status::TRIALING );
}
}
🤖 Prompt for AI Agents
In inc/models/class-membership.php around lines 2435 to 2439, guard the
get_customer() call before invoking get_email_verification() and replace the raw
string comparison with a canonical helper that encapsulates the tri-state
(verified/pending/required) logic; specifically, check that
$this->get_customer() returns an object before calling its email verification
API, call the centralized email-verification helper (e.g.,
Customer::is_email_verification_pending() or a Membership-level helper) to
decide whether verification blocks trialing, and ensure the signup flow or
shared helper is the single place that sets and evaluates the email_verification
value so only plans that require verification will prevent moving status from
PENDING to TRIALING.

Expand Down
Loading