How to Clone a Subsite in WordPress Multisite

In this tutorial, I want to dive deep into the steps you need to take if you want to clone a specific subsite of your WordPress Multisite network. The process is not very difficult, but there are some moments you will need to keep in mind.

We will also take a look at two different approaches – I will show you how to do it with the help of the plugin and also programmatically.

Let’s jump into it.

Method 1. Using a Plugin

Actually, cloning subsites in your WordPress multisite network can be done with a single click in the WordPress admin dashboard easily. If that’s what you’re looking for, then the first method here is definitely for you.

Don’t forget to network activate my Duplicate Site for WordPress Multisite plugin before following any instructions from this chapter.

1.1 Configure which post types and post statuses you want to duplicate, whether you want to assign users, and copy media files

First things first, we need to open the plugin settings page in the Network Admin dashboard. Let’s go to Settings > Duplicate Site.

On this page, you can find some settings that will not only make the duplication process more precise but may also speed it up for you.

Duplicate Site for WordPress Multisite settings page
Settings > Duplicate Site

Above is just an example of my settings page; you can configure it the way you need.

In my case, for example, I do not want to copy media files, because the cloned subsites’ content will still have direct media links, which is totally fine with me. So, first, I unchecked the “Duplicate files from duplicated sites uploads directory” checkbox, and second, if I do not want to copy media files, I definitely do not need the attachment post type, so I excluded it in the Excluded Post Types field.

I also do not need a custom post type event in my cloned subsites, so I added it as well.

Last but not least, you can decide whether all the users from the original subsite should be added to the cloned subsite as well.

1.2 Choose database tables to clone on a site-specific basis

The next thing we need to do is to choose precisely which database tables of the original subsite we’re about to clone.

Each subsite across your WordPress Multisite network can have a different set of database tables – it is defined by the installed plugins, which is why it can be configured for each subsite you’re about to clone individually.

Choose database tables to clone together with a subsite

The tables that are never meant to be cloned (for example, Action Scheduler database tables can be pretty heavy) are excluded by default.

1.3 One-click clone a subsite

Once you have finished with the configuration, you can visit the “Sites > All Sites” page and clone a subsite within your WordPress Multisite network.

As I already mentioned before, with the help of the plugin, it can be done with a single click:

WordPress Multisite clone site example
How to clone a subsite with the Duplicate Site for WordPress Multisite plugin.

Method 2. How to Clone a Subsite Programmatically Without Plugins

If you’re trying to avoid using any plugin, it is totally OK. However, duplicating sub-sites within a multisite network could be quite a complex task to achieve with your bare hands in code.

2.1 Create a clean subsite with wpmu_create_blog()

The first part of our cloning function will be the run of the wpmu_create_blog() function.

// first of all, get some information of an original subsite
$original_blog_id = 1;
$original_blog = get_site( $original_blog_id );

$new_blog_id = wpmu_create_blog(
	$original_blog->domain,
	$original_blog->path . '-copy',
	get_blog_option( $original_blog_id, 'blogname' ) . ' Copy',
	get_current_user_id(),
	array(
		'public' => $original_blog->public,
		'archived' => $original_blog->archived,
		'mature' => $original_blog->mature,
		'spam' => $original_blog->spam,
		'deleted' => $original_blog->deleted,
	),
	get_current_network_id()
);

The code above works perfectly for sub-directories installation. If you want to use it for the sub-domains setup, it could be a little bit different, specifically lines 6 and 7 in the code.

2.2 Duplicate database tables

When it comes to cloning the site content and its options, our goal is to avoid running a pair of switch_to_blog() and restore_current_blog() functions thousands of times or so.

That’s why it is better to duplicate everything on the database level.

For example, this is how we can duplicate all posts:

global $wpdb;

$table_names = array( 'wp_posts', 'wp_postmeta' );

foreach( $table_names as $table_name ) {
	$new_table_name = str_replace( "wp_", "wp_{$new_blog_id}_", $table_name );
	
	// create an empty table
	$wpdb->query(
		"
		CREATE TABLE IF NOT EXISTS `$new_table_name` LIKE `$table_name`
		"
	);
	
	// clone original table there
	$wpdb->query(
		"
		INSERT `$new_table_name` SELECT * FROM `$table_name`
		"
	);

}

Keep in mind that the code snippet above is over-simplified, and you will also need to consider the following things when cloning your database tables:

  • When cloning the options table wp_options, you need to exclude the following system options from overriding: siteurl, home, upload_path, fileupload_url, upload_url_path, admin_email, blogname, otherwise your cloned site will not work.
  • When cloning the posts table wp_posts, you may want to exclude specific post types or statuses like revision.
  • When cloning the postmeta table wp_postmeta, you will definitely need to exclude the following meta keys: _edit_lock and _edit_last.

Of course, all these moments have already been taken care of in the plugin approach.

2.3 Add users to a cloned subsite

The users are a global entity within any WordPress Multisite network, which is why we shouldn’t be worried about copying wp_users and wp_usermeta tables, however, if we want the users from the original subsite to be able to sign in to a cloned subsite, we need to add them with the add_user_to_blog() function.

$user_query = new WP_User_Query( array(
	'blog_id' => $original_blog_id,
	'number' => -1,
) );

foreach( $user_query->get_results() as $user ) {
	add_user_to_blog( $new_blog_id, $user->ID, $user->roles[0] );
}

The thing here is that the add_user_to_blog() function doesn’t accept multiple roles as an array, so maybe you will need to add roles manually by additionally duplicating some values from the wp_capabilities database option.

More info about adding users to blogs, you can read here.

2.4 Duplicate media files

Each directory in the uploads folder should be cloned recursively.

Here is the function itself:

function rudr_recurse_copy( $from, $to ) {

	$from = untrailingslashit( $from );
	$to = untrailingslashit( $to );

	$dir = opendir( $from );
	@mkdir( $to );

	while( false !== ( $file = readdir( $dir ) ) ) {
		// skip what we don't need
		if( $file == '.' || $file == '..' ) {
			continue;
		}
		// recurse copy
		if( is_dir( "{$from}/{$file}" ) ) {
			rudr_recurse_copy( "{$from}/{$file}", "{$to}/{$file}" );
		} else {
			copy( "{$from}/{$file}", "{$to}/{$file}" );
		}
	}

	closedir( $dir );

}

Here is how we need to use it:

$upload_dir = wp_upload_dir();

switch_to_blog( $new_blog_id );
$new_upload_dir = wp_upload_dir();

rudr_recurse_copy( $upload_dir[ 'basedir' ], $new_upload_dir[ 'basedir' ] );

If you have any questions, feel free to ask in the comments section below.

Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 15 years I've been doing my best to share with you some superb WordPress guides and tips for free.

Need some developer help? Contact me

Follow me on X