Forked from ideadude/tag_and_delete_inactive_users.php
Last active
October 31, 2023 12:06
-
-
Save kimcoleman/3ed874aa3156bd0bd4fafd4148157840 to your computer and use it in GitHub Desktop.
Script to tag and delete inactive PMPro Members and users from WordPress.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Script to locate, tag, export, then delete inactive users in your Paid Memberships Pro / WordPress website. | |
* | |
* Once this snippet is in the site, admins can run the process by visiting /?delete_inactive_users=1 in the WordPress admin. | |
* Always back up user data before running any bulk delete script and remove this code after the process is done. | |
*/ | |
function my_pmpro_tag_inactive_users() { | |
if ( ! defined( 'PMPRO_VERSION' ) ) { | |
exit; | |
} | |
// First, run a script to add a usermeta field that tags inactive users based on rules in the script. | |
if ( ! empty( $_REQUEST['tag_inactive_users'] ) && current_user_can( 'manage_options' ) ) { | |
global $wpdb; | |
// Get the limit of users to tag per run from URL parameter. | |
if ( ! empty( $_REQUEST['limit'] ) ) { | |
$limit = intval( $_REQUEST['limit'] ); | |
} else { | |
$limit = 10; | |
} | |
// Get the position to start the script from URL parameter. | |
if ( ! empty( $_REQUEST['start'] ) ) { | |
$start = intval( $_REQUEST['start'] ); | |
} else { | |
$start = 0; | |
} | |
// Get the delay to use between script runs from URL parameter. | |
if ( ! empty( $_REQUEST['delay'] ) ) { | |
$delay = intval( $_REQUEST['delay'] ); | |
} else { | |
$delay = 5000; | |
} | |
// Get the flag whether to run the script in batches automatically or manually from URL parameter. | |
if ( ! empty( $_REQUEST['auto'] ) ) { | |
$auto = 1; | |
} else { | |
$auto = 0; | |
} | |
echo "Starting with ID #" . $start . ". " . current_time( 'c' ); | |
echo "<hr />"; | |
$user_ids_to_check = $wpdb->get_col( "SELECT ID FROM $wpdb->users WHERE ID > $start ORDER BY ID LIMIT $limit" ); | |
foreach( $user_ids_to_check as $user_id ) { | |
$user = get_userdata( $user_id ); | |
echo "Checking #" . $user->ID . " " . esc_html( $user->user_email ) . ": "; | |
// Skip if user is not subscriber role. | |
if ( ! in_array( 'subscriber', (array) $user->roles ) ) { | |
echo "User is not a subscriber. Skipping.<br />"; | |
continue; | |
} | |
// Skip if user has logged in within the past 6 months. | |
$logins = pmpro_reports_get_values_for_user( 'logins', $user->ID ); | |
if ( ! empty( $logins ) && ! empty( $logins['last'] ) && strtotime( $logins['last'] ) > strtotime( '-6 months' ) ) { | |
echo "User has logged in within the past 6 months. Skipping.<br />"; | |
continue; | |
} | |
// Skip if the user has any paid order history. | |
$paid_order = $wpdb->get_var( "SELECT id FROM $wpdb->pmpro_membership_orders WHERE user_id = " . $user->ID . " AND total > 0 LIMIT 1" ); | |
if ( ! empty( $paid_order ) ) { | |
echo "User has a paid order. Skipping.<br />"; | |
continue; | |
} | |
// Check if the user has a specific active membership level. | |
// Update these to your level IDs. | |
if ( pmpro_hasMembershipLevel( array( 1, 2, 3 ), $user->ID ) ) { | |
echo "User has a premium membership level. Skipping.<br />"; | |
continue; | |
} | |
// Skip if the user is an author of anything. | |
$posts = $wpdb->get_var( "SELECT ID FROM $wpdb->posts WHERE post_author = " . $user->ID . " LIMIT 1" ); | |
if ( ! empty( $posts ) ) { | |
echo "User has authored something. Skipping.<br />"; | |
continue; | |
} | |
// Add any additional custom checks here. | |
// If we get here, tag the user for deletion. | |
echo "Tagging for deletion.<br />"; | |
wp_set_object_terms( $user->ID, 'inactive', 'my_user_activity' ); | |
} | |
// Set the new position (user ID) to start the next run of the script at. | |
$new_start = $user->ID; | |
$reload_url = admin_url( '?tag_inactive_users=1&limit=' . $limit . "&start=" . $new_start . '&delay=' . $delay . '&auto=' . $auto ); | |
// If auto, run the script again after the delay. | |
if ( ! empty( $user_ids_to_check ) && ! empty( $_REQUEST['auto'] ) ) { | |
echo "<hr />"; | |
echo "Loading " . $reload_url . " in " . $delay . " microseconds."; | |
?> | |
<script> | |
setTimeout( function() { | |
window.location.href = '<?php echo esc_url_raw( $reload_url );?>'; | |
}, <?php echo $delay; ?> ); | |
</script> | |
<?php } else { ?> | |
<hr /> | |
<p><a href="<?php echo esc_url_raw( $reload_url );?>">Click here to load the next batch.</a></p> | |
<?php } | |
exit; | |
} | |
} | |
add_action( 'init', 'my_pmpro_tag_inactive_users' ); | |
/** | |
* Export users tagged as inactive. | |
*/ | |
function my_pmpro_export_inactive_users() { | |
if ( ! defined( 'PMPRO_VERSION' ) ) { | |
exit; | |
} | |
global $wpdb; | |
if ( ! empty( $_REQUEST['export_inactive_users'] ) && current_user_can( 'manage_options' ) ) { | |
function pmpro_enclose( $s ) { | |
return "\"" . str_replace( "\"", "\\\"", $s ) . "\""; | |
} | |
if ( ! empty( $_REQUEST['limit'] ) ) { | |
$limit = intval( $_REQUEST['limit'] ); | |
} else { | |
$limit = 10000; | |
} | |
if ( ! empty( $_REQUEST['start'] ) ) { | |
$start = intval( $_REQUEST['start'] ); | |
} else { | |
$start = 0; | |
} | |
$term = get_term_by( 'slug', 'inactive', 'my_user_activity' ); | |
$sqlQuery = "SELECT u.* FROM $wpdb->term_relationships tr LEFT JOIN $wpdb->users u ON tr.object_id = u.ID WHERE tr.term_taxonomy_id = '" . $term->term_id . "' AND tr.object_id > $start ORDER BY tr.object_id LIMIT $limit"; | |
$users = $wpdb->get_results( $sqlQuery ); | |
echo "ID,user_login,user_nicename,user_email,user_url,user_registered,user_status,display_name\n"; | |
foreach( $users as $user ) { | |
echo $user->ID . ',' | |
. $user->user_login . ',' | |
. $user->user_nicename . ',' | |
. $user->user_email . ',' | |
. $user->user_url . ',' | |
. $user->user_registered .',' | |
. $user->user_status . ',' | |
. pmpro_enclose( $user->display_name ) | |
. "\n"; | |
} | |
exit; | |
} | |
} | |
add_action( 'init', 'my_pmpro_export_inactive_users' ); | |
/** | |
* Delete users tagged as inactive. | |
*/ | |
function my_pmpro_delete_inactive_users() { | |
global $wpdb; | |
if ( ! empty( $_REQUEST['delete_inactive_users'] ) && current_user_can( 'manage_options' ) ) { | |
$term = get_term_by( 'slug', 'inactive', 'my_user_activity' ); | |
if ( ! empty( $_REQUEST['limit'] ) ) { | |
$limit = intval( $_REQUEST['limit'] ); | |
} else { | |
$limit = 10; | |
} | |
if ( ! empty( $_REQUEST['start'] ) ) { | |
$start = intval( $_REQUEST['start'] ); | |
} else { | |
$start = 0; | |
} | |
if ( ! empty( $_REQUEST['delay'] ) ) { | |
$delay = intval( $_REQUEST['delay'] ); | |
} else { | |
$delay = 5000; | |
} | |
if ( ! empty( $_REQUEST['auto'] ) ) { | |
$auto = 1; | |
} else { | |
$auto = 0; | |
} | |
if ( ! empty( $_REQUEST['delete'] ) ) { | |
$delete = 1; | |
} else { | |
$delete = 0; | |
} | |
$sqlQuery = "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = '" . $term->term_id . "' AND object_id > $start ORDER BY object_id LIMIT $limit"; | |
$user_ids_to_delete = $wpdb->get_col( $sqlQuery ); | |
echo "<ul>"; | |
foreach ( $user_ids_to_delete as $user_id ) { | |
$user = get_userdata( $user_id ); | |
echo '<li>#' . $user_id . ' <a href="' . esc_url_raw( admin_url( 'user-edit.php?user_id=' . $user->ID ) ) . '">' . $user->display_name . ' (' . $user->user_email . ')' . '</a>'; | |
if ( ! empty( $_REQUEST['delete'] ) ) { | |
// Delete rows from these 3 tables: term_relationships, usermeta, and users. | |
// This will not delete data from PMPro orders or memberships users table. | |
$query1 = "DELETE FROM $wpdb->term_relationships WHERE term_taxonomy_id = '" . $term->term_id . "' AND object_id = '" . $user_id . "' LIMIT 1"; | |
$r1 = $wpdb->query( $query1 ); | |
$query2 = "DELETE FROM $wpdb->usermeta WHERE user_id = '" . $user->ID . "'"; | |
$r2 = $wpdb->query( $query2 ); | |
$query3 = "DELETE FROM $wpdb->users WHERE ID = '" . $user->ID . "' LIMIT 1"; | |
$r3 = $wpdb->query( $query3 ); | |
echo ' <strong>DELETED</strong>'; | |
} | |
echo '</li>'; | |
} | |
echo "</ul>"; | |
// Set the new position (user ID) to start the next run of the delete script at. | |
$new_start = $user->ID; | |
$reload_url = admin_url( '?delete_inactive_users=1&limit=' . $limit . "&start=" . $new_start . '&delay=' . $delay . '&auto=' . $auto . '&delete=' . $delete ); | |
// If auto, run the script again after the delay. | |
if ( ! empty( $user_ids_to_delete ) && ! empty( $_REQUEST['auto'] ) ) { | |
echo "<hr />"; | |
echo "Loading " . $reload_url . " in " . $delay . " microseconds seconds."; | |
?> | |
<script> | |
setTimeout( function() { | |
window.location.href = '<?php echo esc_url_raw( $reload_url );?>'; | |
}, <?php echo $delay; ?> ); | |
</script> | |
<?php } else { ?> | |
<hr /> | |
<p><a href="<?php echo esc_url_raw( $reload_url );?>">Click here to load the next batch.</a></p> | |
<?php } | |
exit; | |
} | |
} | |
add_action( 'init', 'my_pmpro_delete_inactive_users' ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment