How to Delete a WordPress Site and All of Its Users

Perhaps you’ve built an awesome, massive WordPress Multisite website. Now you need a way to delete entire blogs, and all of their users, in one go. Maybe you charge subscriptions, and want to delete them if their subscription expires, for example.

The code below, handily commented to help you understand it better, will do just that.

Specifically, it will delete:

  1. All users who are a part of that site – so be careful that this is what you want. If you have users who are shared between multiple sites, I’ll go over that below.
  2. The actual blog itself.
  3. It will also attempt to delete all orphaned tables that aren’t deleted when the site itself is deleted. These occur because WordPress only deletes WordPress tables. Plugins are supposed to handle this, but even WooCommerce, owned by Automattic themselves, doesn’t delete all of them.

This is one of those BACK UP YOUR DATABASE situations, for sure!


function delete_blog_and_its_users($site_id) {
if ($site_id) { // Pass the site's ID. This can be found in WordPress → My Sites → Sites
switch_to_blog($site_id); // this takes us to the site in question
// delete all users associated with this blog
$user_args = array(
'order' => 'ASC'
);
$users = get_users($user_args);
require_once( ABSPATH . 'wp-admin/includes/user.php' ); // required to delete users from a blog
require_once( ABSPATH . 'wp-admin/includes/ms.php' ); // required to delete users from ALL blogs on the network
foreach($users as $user) {
//echo '<p>'.$user->ID.' | '.$user->user_login.'</p>'; // comment out wpmu_delete_users in the next line and uncomment this if you want to test what users will be returned
wpmu_delete_user($user->ID, null);

} // foreach($users as $user)

// delete the site
wpmu_delete_blog($site_id, true); // does the actual deleting, and also requires ms.php to be included as per previous code in the function

// delete additional, orphaned tables in the database, this should happen automatically with clean_up_db_after_delete_blog

restore_current_blog(); // reverses switch_to_blog

} // if ($site_id)
} // end of the delete_blog_and_its_users function

// Cleanup orphaned database tables when a site is deleted
// Runs automatically when you run the function above
// originally from here: https://core.trac.wordpress.org/ticket/43162
add_action( 'delete_blog', 'clean_up_db_after_delete_blog', 10, 2 );
function clean_up_db_after_delete_blog( $blog_id, $drop ) {

if ( true == $drop ) {

// SELECT all tables relating to a specific blog id and add them to wpmu_drop_tables
global $wpdb;
$prep_query = $wpdb->prepare( "SELECT table_name FROM information_schema.TABLES WHERE table_name LIKE %s;", $wpdb->esc_like( "{$wpdb->base_prefix}{$blog_id}_" ) . '%' );
$table_list = $wpdb->get_results( $prep_query, ARRAY_A );

add_filter( 'wpmu_drop_tables', function ( $filter_list ) use ( $table_list ) {

foreach( $table_list as $index => $data ) {
$filter_list[] = $data['table_name'];
}

return array_unique( $filter_list );

});

// add any specific tables that aren't being removed, minus their blog prefix, to the list below
add_filter('wpmu_drop_tables', 'woocommerce_drop_additional_tables');
function woocommerce_drop_additional_tables($tables) {
global $wpdb;

$tables[] = $wpdb->prefix . 'wc_orders';
$tables[] = $wpdb->prefix . 'wc_orders_meta';
$tables[] = $wpdb->prefix . 'wc_order_addresses';
$tables[] = $wpdb->prefix . 'wc_order_operational_data';
$tables[] = $wpdb->prefix . 'wc_product_attributes_lookup';

return $tables;
}

}
}

If you don’t want to delete all users forever, from all sites in your network, you can just remove them from the specific blog you’re passing via $site_id by changing this line of code, in the first function:


wpmu_delete_user($user->ID, null);

to this:


wp_delete_user($user->ID, null);

We just removed two letters, but now the users will not be deleted, just removed from that blog. Though, if that’s what you want, then you don’t need any of the user handling…since you’ll be deleting the blog anyway.

Up Next: How to Get All Taxonomy Terms in WordPress Which Have No Posts