Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kimcoleman/3ed874aa3156bd0bd4fafd4148157840 to your computer and use it in GitHub Desktop.
Save kimcoleman/3ed874aa3156bd0bd4fafd4148157840 to your computer and use it in GitHub Desktop.
Script to tag and delete inactive PMPro Members and users from WordPress.
<?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