Forked from devinsays/delete-customers-without-orders.php
Created
December 9, 2024 13:30
-
-
Save tiendungdev/fd21f817f3ba6abbaff4172d06a35455 to your computer and use it in GitHub Desktop.
Deletes users with customer role in WooCommerce that do not have orders.
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 | |
/** | |
* Deletes customers without orders | |
* | |
* To run the script: | |
* wp eval-file delete-customers-without-orders.php | |
*/ | |
// Query for customers registered since this date. | |
$date_after = '2000-01-01'; | |
// Don't delete accounts that have been created in the last 30 days. | |
$timeframe = strtotime( '-30 seconds', time() ); | |
$date_before = date( 'Y-m-d', $timeframe ); | |
WP_CLI::log( "Finding all users registered between {$date_after} and {$date_before}." ); | |
WP_CLI::log( ' ' ); | |
$customer_ids = find_customer_ids_registered( $date_after, $date_before ); | |
WP_CLI::success( 'Found ' . count( $customer_ids ) . ' customer accounts to verify.' ); | |
WP_CLI::log( '' ); | |
foreach ( $customer_ids as $customer_id ) { | |
$user = get_user_by( 'id', $customer_id ); | |
$role_eligble_for_deletion = user_role_eligible_for_delete( $user ); | |
if ( ! $role_eligble_for_deletion ) { | |
WP_CLI::log( "Customer ID: {$customer_id} has a role that is not eligible for deletion." ); | |
continue; | |
} | |
$user_has_posts = customer_has_posts( $customer_id ); | |
if ( $user_has_posts ) { | |
WP_CLI::log( "Customer ID: {$customer_id} has posts." ); | |
continue; | |
} | |
$user_has_order_postmeta = user_has_order_postmeta( $customer_id ); | |
if ( $user_has_order_postmeta ) { | |
WP_CLI::log( "Customer ID: {$customer_id} has order postmeta." ); | |
continue; | |
} | |
if ( wpcli_is_hpos_enabled() ) { | |
$user_has_order_meta = user_has_orders_meta( $customer_id ); | |
if ( $user_has_order_meta ) { | |
WP_CLI::log( "Customer ID: {$customer_id} has order meta." ); | |
continue; | |
} | |
} | |
// Any other checks you need to do? | |
// Need to check for reviews or comments? | |
WP_CLI::log( "Deleting customer: {$customer_id}" ); | |
delete_customer( $customer_id ); | |
WP_CLI::success( "Customer deleted: {$customer_id}" ); | |
} | |
/** | |
* Return Customer IDs registered before a date and from a date. | |
* | |
* @param string $date_after Find after this date (including the date). | |
* @param string $date_before Find before this date (including the date). | |
* | |
* @return array|object|\stdClass[]|null | |
*/ | |
function find_customer_ids_registered( string $date_after = '', string $date_before = '' ) { | |
global $wpdb; | |
$query = "SELECT DISTINCT users.ID FROM {$wpdb->users} users | |
WHERE users.user_registered <= %s | |
"; | |
$datetime = strtotime( $date_before ); | |
$date_before = date( 'Y-m-d 23:59:59', $datetime ); | |
$prepared_arguments = [ $date_before ]; | |
if ( $date_after ) { | |
$datetime_after = strtotime( $date_after ); | |
$date_after = date( 'Y-m-d 23:59:59', $datetime_after ); | |
$query .= ' AND users.user_registered >= %s'; | |
$prepared_arguments[] = $date_after; | |
} | |
$query = $wpdb->prepare( | |
$query, | |
$prepared_arguments | |
); | |
return $wpdb->get_col( $query ); | |
} | |
/** | |
* Check if customer has a role. | |
* | |
* @param object $user | |
* @return bool | |
*/ | |
function user_role_eligible_for_delete( $user ) { | |
$can_delete = true; | |
// Customer does not have any roles set, so we can delete. | |
if ( ! $user->roles ) { | |
return true; | |
} | |
// This covers the case where customer may have multiple roles. | |
// If any of the roles is not subscriber or customer, we cannot delete. | |
foreach ( $user->roles as $role ) { | |
if ( ! in_array( $role, [ 'subscriber', 'customer' ], true ) ) { | |
$can_delete = false; | |
} | |
} | |
return $can_delete; | |
} | |
/** | |
* Check if user has posts. | |
* | |
* @return bool | |
*/ | |
function customer_has_posts( $user_id ) { | |
global $wpdb; | |
$posts = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_author = $user_id LIMIT 1" ); | |
if ( $posts ) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* User has a postmeta key assigned for _customer_user. | |
* | |
* @param int $user_id | |
* @return bool | |
*/ | |
function user_has_order_postmeta( $user_id ) { | |
global $wpdb; | |
$meta = $wpdb->get_col( "SELECT ID FROM {$wpdb->postmeta} WHERE meta_key = '_customer_user' AND meta_value = $user_id LIMIT 1" ); | |
if ( $meta ) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* User has a ordermeta key assigned for _customer_user. | |
* | |
* @param int $user_id | |
* @return bool | |
*/ | |
function user_has_orders_meta( $user_id ) { | |
global $wpdb; | |
$meta = $wpdb->get_col( "SELECT ID FROM {$wpdb->orders_meta} WHERE meta_key = '_customer_user' AND meta_value = $user_id LIMIT 1" ); | |
if ( $meta ) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Checks if HPOS is enabled. | |
* | |
* @return bool | |
*/ | |
function wpcli_is_hpos_enabled() { | |
return class_exists( OrderUtil::class ) && OrderUtil::custom_orders_table_usage_is_enabled(); | |
} | |
/** | |
* Does a direct SQL query to delete the customer. | |
* This is much faster than wp_delete_user(). | |
* | |
* @param integer $customer_id Customer ID. | |
*/ | |
function delete_customer( $customer_id ) { | |
global $wpdb; | |
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}usermeta WHERE user_id = %d", $customer_id ) ); | |
$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}users WHERE ID = %d", $customer_id ) ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment