PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.5
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.5
1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk All 48 releases
← All changes | api/Resource/CustomerResource.php +30 -24 1.6.1 → 1.6.5 View file →
@@ -135,13 +135,17 @@
135 135 $email = Arr::get($data, 'email');
136 136 $data = static::resolveCustomerName($data);
137 137
138 138 $data['purchase_value'] = [];
139 - $customer = static::getQuery()->firstOrCreate(
140 - ['email' => $email],
141 - $data
142 - );
143 139
140 + // Preserve an established account link; otherwise reuse the email row
141 + // without linking it. Only the verification flow can claim guest history.
142 + $ownerId = (int) Arr::get($data, 'user_id');
143 + $customer = $ownerId ? static::getQuery()->where('user_id', $ownerId)->orderBy('id')->first() : null;
144 + if (!$customer) {
145 + $customer = static::getQuery()->firstOrCreate(['email' => $email], $data);
146 + }
147 +
144 148 if (empty($customer)) {
145 149 return static::makeErrorResponse([
146 150 ['code' => 400, 'message' => __('Customer creation failed.', 'fluent-cart')]
147 151 ]);
@@ -146,13 +150,22 @@
146 150 ['code' => 400, 'message' => __('Customer creation failed.', 'fluent-cart')]
147 151 ]);
148 152 }
149 153
150 - $isUserAttached = false;
151 - $user = get_user_by('email', $email);
152 - if ($user) {
153 - $customer->update(['user_id' => $user->ID]);
154 - $isUserAttached = true;
154 + // Linking happens only where identity is established. A row that
155 + // already existed is never claimed here: firstOrCreate() may have found
156 + // somebody else's record by its address. A fresh row is linked to the
157 + // account holding its email only for an actor with authority over that
158 + // account (an admin screen, the MCP tools) or when the caller supplied
159 + // the user_id it established itself (a signed-in checkout, the User
160 + // API). An anonymous caller — a guest at checkout — links nothing.
161 + $isUserAttached = (bool) $customer->user_id;
162 + if ($customer->wasRecentlyCreated && !$isUserAttached) {
163 + $user = get_user_by('email', $email);
164 + if ($user && get_current_user_id() && current_user_can('edit_user', $user->ID)) {
165 + $customer->update(['user_id' => $user->ID]);
166 + $isUserAttached = true;
167 + }
155 168 }
156 169
157 170 if (Arr::get($data, 'wp_user') === 'yes' && !$isUserAttached) {
158 171 $isUserCreated = \FluentCart\App\Services\AuthService::createUserFromCustomer($customer);
@@ -410,29 +423,22 @@
410 423 }
411 424
412 425 $currentUser = get_user_by('ID', get_current_user_id());
413 426
414 - // Try to get the existing customer
415 - $query = Customer::query()->where('user_id', $currentUser->ID)
416 - ->orWhere('email', $currentUser->user_email)
417 - ->with(['billing_address', 'shipping_address']);
427 + // Reading the current customer must not claim a record by email.
428 + $existingCustomer = Customer::query()->where('user_id', $currentUser->ID)
429 + ->orderBy('id', 'ASC')
430 + ->with(['billing_address', 'shipping_address'])
431 + ->first();
418 432
419 -
420 - $existingCustomer = $query->first();
421 -
422 - // Return if found
423 433 if ($existingCustomer) {
424 - if ($existingCustomer->user_id != $currentUser->ID) {
425 - // Update the user_id if it doesn't match
426 - $existingCustomer->user_id = $currentUser->ID;
427 - $existingCustomer->save();
428 - }
429 -
430 434 static::$currentCustomerRuntimeCache = $existingCustomer;
431 435 return $existingCustomer;
432 436 }
433 437
434 - if (!$createIfNotExists) {
438 + if (!$createIfNotExists || Customer::query()->where('email', $currentUser->user_email)->exists()) {
439 + // Do not create a duplicate or expose an unclaimed customer to a getter.
440 + // Email confirmation links the existing row before dashboard access.
435 441 return null;
436 442 }
437 443
438 444 $userId = $currentUser->ID;