Created
October 28, 2023 16:42
-
-
Save ideadude/024994004e4ba39529ff193f5b18f7c1 to your computer and use it in GitHub Desktop.
Script to tag and delete inactive users from WP/PMPro.
This file contains hidden or 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 | |
/** | |
* Tag inactive users. | |
* One time script. To run, visit /?delete_inactive_users=1 as an admin. | |
* An inactive user: | |
* - Has no logins within the last 2 years. | |
* - Has no paid orders. | |
* - Has no support tickets. | |
* ? Add inactive taxonomy to users? Then delete users in that taxonomy? | |
* Get users who are tagged for deletion: | |
* SELECT u.ID, u.user_email, u.user_registered | |
* FROM wp_users u | |
* LEFT JOIN wp_usermeta um ON u.ID = um.user_id | |
* AND um.meta_key = 'pmpro_inactive_user_to_delete' | |
* AND um.meta_value = 1; | |
*/ | |
function my_tag_inactive_users() { | |
if ( !empty( $_REQUEST['tag_inactive_users'] ) && current_user_can( 'manage_options' ) ) { | |
global $wpdb; | |
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; | |
} | |
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 ) . ": "; | |
// Check if doesn't have subscriber role. | |
if ( ! in_array( 'subscriber', (array) $user->roles ) ) { | |
echo "User is not a subscriber. Skipping.<br />"; | |
continue; | |
} | |
// Check for recent login. | |
$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; | |
} | |
// Check for paid orders. | |
$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 membership levels. NOTE: Change these level IDs. | |
if ( pmpro_hasMembershipLevel( array( 20, 21, 6, 15, 16, 17, 18, 19 ), $user->ID ) ) { | |
echo "User has a premium membership level. Skipping.<br />"; | |
continue; | |
} | |
// Check if is 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; | |
} | |
// If we get here, tag them for deletion. | |
echo "Tagging for deletion.<br />"; | |
wp_set_object_terms( $user->ID, 'inactive', 'my_user_activity' ); | |
} | |
$new_start = $user->ID; | |
$reload_url = admin_url( '?tag_inactive_users=1&limit=' . $limit . "&start=" . $new_start . '&delay=' . $delay . '&auto=' . $auto ); | |
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_tag_inactive_users' ); | |
/** | |
* Export users tagged as inactive. | |
*/ | |
function my_export_inactive_users() { | |
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_export_inactive_users' ); | |
/** | |
* Delete users tagged as inactive. | |
*/ | |
function my_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'] ) ) { | |
// We are just deleting rows from these 3 tables. Should be quicker and avoid deleting | |
// PMPro orders or things we want. Those orders will be orphaned though. | |
// wp_delete_user( $user->ID ); | |
$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>"; | |
$new_start = $user->ID; | |
$reload_url = admin_url( '?delete_inactive_users=1&limit=' . $limit . "&start=" . $new_start . '&delay=' . $delay . '&auto=' . $auto . '&delete=' . $delete ); | |
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_delete_inactive_users' ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment