PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 1.1.0
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v1.1.0
1.6.0 1.5.1 1.5.0 1.4.0 1.3.0 trunk 0.0.1 1.0.0 1.1.0 1.1.1 1.1.2 1.2.0
suredonation / inc / donor-user-link.php

donor-user-link.php in SureDonation – Donation Forms, Fundraising Campaigns & Donor Management 1.1.0, at inc/donor-user-link.php

99 lines 2.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Donor-User Linking
4 *
5 * Links WordPress users to donor records on login.
6 *
7 * @package SureDonation
8 */
9
10 namespace SureDonation\Inc;
11
12 use SureDonation\Inc\Database\Tables\Donors;
13 use SureDonation\Inc\Traits\Get_Instance;
14
15 // Exit if accessed directly.
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit;
18 }
19
20 /**
21 * Donor_User_Link class.
22 *
23 * @since 1.0.0
24 */
25 class Donor_User_Link {
26 use Get_Instance;
27
28 /**
29 * Constructor.
30 *
31 * @since 1.0.0
32 */
33 private function __construct() {
34 add_action( 'wp_login', [ $this, 'link_donor_on_login' ], 10, 2 );
35 }
36
37 /**
38 * Link donor record to WP user on login.
39 *
40 * If the logged-in user's email matches a donor without a user_id,
41 * link them automatically.
42 *
43 * @param string $user_login Username.
44 * @param \WP_User $user WP_User object.
45 * @return void
46 * @since 1.0.0
47 */
48 public function link_donor_on_login( $user_login, $user ) {
49 unset( $user_login );
50
51 if ( ! $user instanceof \WP_User || empty( $user->user_email ) ) {
52 return;
53 }
54
55 $donor = Donors::get_by_email( $user->user_email );
56
57 if ( ! $donor || empty( $donor['id'] ) ) {
58 return;
59 }
60
61 $donor_id = is_numeric( $donor['id'] ) ? (int) $donor['id'] : 0;
62 if ( $donor_id <= 0 ) {
63 return;
64 }
65
66 // Already linked to this user.
67 $existing_user_id = isset( $donor['user_id'] ) && is_numeric( $donor['user_id'] ) ? (int) $donor['user_id'] : 0;
68 if ( $existing_user_id === $user->ID ) {
69 return;
70 }
71
72 // Link the donor to this WP user (only if not linked to a different user).
73 // Direct $wpdb->update so the WHERE clause can carry the
74 // "still unlinked" condition atomically. A read-then-write via
75 // Donors::update() would race against another concurrent login
76 // that shares this email (email-change flows, shared-mailbox
77 // households) and could silently overwrite a link the other
78 // request just established.
79 if ( $existing_user_id <= 0 ) {
80 global $wpdb;
81 $donors_table = $wpdb->prefix . 'suredonation_donors';
82 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Atomic conditional update; the abstraction layer doesn't support multi-column WHERE.
83 $wpdb->update(
84 $donors_table,
85 [
86 'user_id' => $user->ID,
87 'updated_at' => current_time( 'mysql' ),
88 ],
89 [
90 'id' => $donor_id,
91 'user_id' => 0,
92 ],
93 [ '%d', '%s' ],
94 [ '%d', '%d' ]
95 );
96 }
97 }
98 }
99