Skip to content

Instantly share code, notes, and snippets.

@petertwise
Last active November 13, 2025 19:46
Show Gist options
  • Select an option

  • Save petertwise/cae97f0165709d11549faa9c3f3f30b4 to your computer and use it in GitHub Desktop.

Select an option

Save petertwise/cae97f0165709d11549faa9c3f3f30b4 to your computer and use it in GitHub Desktop.
GiveWP Auto-connect existing WP users to GiveWP Donors
<?php
// Add this snippet to your theme code, or integrate it into a plugin.
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Bail if GiveWP is not active
if ( ! class_exists( 'Give' ) ) {
return;
}
// GIVEWP - AUTO-LINK DONORS TO EXISTING WordPress USERS
// This solves an issue where GiveWP sometimes creates donor records without properly linking them to existing WP users
/**
* Link a GiveWP donor record to an existing WordPress user by email address
*
* This function searches for a donor record with the given email that has user_id = 0,
* and if found, links it to the corresponding WordPress user. It also grants the
* 'give_donor' capability to the user if they don't already have it.
*
* @since 1.0.0
*
* @param string $email The email address to search for.
*
* @return bool True if a donor was successfully linked, false otherwise.
*/
function squarecandy_give_auto_link_donor_to_user( $email ) {
global $wpdb;
// Validate email.
if ( empty( $email ) || ! is_email( $email ) ) {
return false;
}
// Look for existing WordPress user with this email.
$user = get_user_by( 'email', $email );
if ( ! $user ) {
return false;
}
// Look for existing donor record with same email and user_id = 0.
$donor = $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}give_donors WHERE email = %s AND user_id = 0",
$email
)
);
if ( ! $donor ) {
return false;
}
// Link the donor record to the user.
$update_result = $wpdb->update(
$wpdb->prefix . 'give_donors',
array( 'user_id' => $user->ID ),
array( 'id' => $donor->id ),
array( '%d' ),
array( '%d' )
);
if ( false === $update_result ) {
// Database update failed.
give_record_log(
'GiveWP Auto-Link Donor Failed',
sprintf(
// translators: 1: donor ID, 2: user ID, 3: email.
__( 'Failed to link donor ID %1$d to user ID %2$d (email: %3$s)', 'give' ),
$donor->id,
$user->ID,
$email
),
0,
'error'
);
return false;
}
// Add give_donor capability if they don't have it.
if ( ! user_can( $user->ID, 'give_donor' ) ) {
$user->add_cap( 'give_donor' );
}
// Log the successful linking.
give_record_log(
'GiveWP Auto-Link Donor Success - ' . $email,
sprintf(
// translators: 1: donor ID, 2: user ID, 3: email.
__( 'Successfully linked donor ID %1$d to user ID %2$d (email: %3$s)', 'give' ),
$donor->id,
$user->ID,
$email
),
0,
'sale' // Using 'sale' as the log type because it maps to INFO in GiveWP's log system (not error).
);
// Clear any cached donor data.
Give_Cache::delete_group( $donor->id, 'give-donors' );
return true;
}
/**
* Automatically link donor to existing user when a new donation is processed
*
* This function runs on the 'give_insert_payment' hook to ensure that
* donors are linked to existing WordPress users at the time of donation.
*
* @since 1.0.0
*
* @param int $payment_id The ID of the payment.
* @param array $payment_data The payment data.
*
* @return void
*/
function squarecandy_give_auto_link_donor_on_donation( $payment_id, $payment_data ) {
// Get the donor email from payment data.
$email = isset( $payment_data['user_info']['email'] ) ? $payment_data['user_info']['email'] : '';
if ( empty( $email ) ) {
return;
}
// Attempt to link the donor to an existing user.
squarecandy_give_auto_link_donor_to_user( $email );
}
add_action( 'give_insert_payment', 'squarecandy_give_auto_link_donor_on_donation', 10, 2 );
/**
* Daily cron job to scan all donors and link them to existing WordPress users
*
* This function searches for all donor records with user_id = 0 and attempts
* to link them to existing WordPress users by email address.
*
* @since 1.0.0
*
* @return void
*/
function squarecandy_give_auto_link_all_donors_cron() {
global $wpdb;
// Get all donors with user_id = 0, empty, or null.
$unlinked_donors = $wpdb->get_results(
"SELECT id, email FROM {$wpdb->prefix}give_donors WHERE user_id = 0 OR user_id IS NULL OR user_id = ''"
);
if ( empty( $unlinked_donors ) ) {
return;
}
$linked_count = 0;
foreach ( $unlinked_donors as $donor ) {
// Attempt to link this donor to an existing user.
$result = squarecandy_give_auto_link_donor_to_user( $donor->email );
if ( $result ) {
$linked_count++;
}
}
// Log the results of the cron job.
if ( $linked_count > 0 ) {
give_record_log(
'GiveWP Auto-Link Donors Cron',
sprintf(
// translators: 1: number of donors linked, 2: total number of unlinked donors.
__( 'Cron job linked %1$d of %2$d unlinked donors to existing WordPress users.', 'give' ),
$linked_count,
count( $unlinked_donors )
),
0,
'sale' // Using 'sale' as the log type because it maps to INFO in GiveWP's log system (not error).
);
}
}
add_action( 'squarecandy_give_auto_link_donors_cron', 'squarecandy_give_auto_link_all_donors_cron' );
/**
* Schedule the daily cron job for auto-linking donors
*
* @since 1.0.0
*
* @return void
*/
function squarecandy_give_schedule_auto_link_cron() {
if ( ! wp_next_scheduled( 'squarecandy_give_auto_link_donors_cron' ) ) {
wp_schedule_event( time(), 'daily', 'squarecandy_give_auto_link_donors_cron' );
}
}
add_action( 'after_setup_theme', 'squarecandy_give_schedule_auto_link_cron' );
/**
* Unschedule the cron job when deactivating or switching themes
*
* @since 1.0.0
*
* @return void
*/
function squarecandy_give_unschedule_auto_link_cron() {
$timestamp = wp_next_scheduled( 'squarecandy_give_auto_link_donors_cron' );
if ( $timestamp ) {
wp_unschedule_event( $timestamp, 'squarecandy_give_auto_link_donors_cron' );
}
}
add_action( 'switch_theme', 'squarecandy_give_unschedule_auto_link_cron' );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment