What do you mean by WordPress Multisite Migration?

Part of my responsibilities involves creating and maintaining sites within many different WordPress Multisite networks.  Recently, I ended up doing a lot of Googling for WordPress Multisite migration. It’s pretty easy to find a lot of results for going from a multisite network to a single site, but I was having a hard time finding anything which involved migrating from one multisite network to another.

Why?

Generally, I’d prefer having thought out my multisite needs enough so that I don’t need to migrate sites. One of my preferences is to keep sites with similar functionality together, but recently I had a client that started selling pizzas.

They weren’t sure which plugin they were interested in using. WP-Pizza and GloriaFood are the two contenders right now, but they’re still exploring options. They had five sites on one of our networks, and we decided it would be cleaner to create a separate network for them to use exclusively. They’d be able to use plugins which we wouldn’t want to have available to other clients, as well as compartmentalizing their sites, making it easier to migrate them in the future.

How?

Google “WordPress Multisite Migration” and you’ll find a lot of options, but most people are migrating a multisite to a single site. I wanted to get the “multisite site to different multisite” migration down so I would be able to do it again in the future.

Step 1 – Export the old site’s database

First thing’s first. You’ll want to use WP-CLI for this. You’ll want to be familiar with your Linux command line to get it installed, and for most of the tasks, we’ll be working on here. I’ll write more on WP-CLI later, as it’s one of the most useful tools to have in your pocket.

wp db query "show tables"

This should return a whole bunch of tables. Here’s a snippet:

| wp_36_term_relationships |
| wp_36_term_taxonomy |
| wp_36_termmeta |
| wp_36_terms |
| wp_38_commentmeta |
| wp_38_comments |
| wp_38_links |
| wp_38_options |
| wp_38_pmxe_exports |
| wp_38_pmxe_google_cats |
| wp_38_pmxe_posts |
| wp_38_pmxe_templates |
| wp_38_postmeta |
| wp_38_posts |
| wp_38_rg_form |
| wp_38_rg_form_meta |
| wp_38_rg_form_view |
| wp_38_rg_incomplete_submissions |
| wp_38_rg_lead |
| wp_38_rg_lead_detail |
| wp_38_rg_lead_detail_long |
| wp_38_rg_lead_meta |
| wp_38_rg_lead_notes |
| wp_38_term_relationships |
| wp_38_term_taxonomy |
| wp_38_termmeta |
| wp_38_terms |
| wp_39_commentmeta |
| wp_39_comments |
| wp_39_links |

If you’ve worked with multisite very often, this will look familiar. If you aren’t as familiar with multisite, it should seem familiar seeing all of your tables starting with wp_ as that’s the WordPress default. In this case, the tables are all named:

wp_siteID_table

This only helps if we know our site ID. WP-CLI to the rescue!

wp site list
+---------+--------------------------------------------+---------------------+---------------------+
| blog_id | url                   | last_updated       | registered          |
+---------+--------------------------------------------+---------------------+---------------------+
...
| 36 | http://examplesite1.com/   | 2018-02-17 17:48:13 | 2018-02-01 15:05:19 |
| 38 | http://sitetotransfer.com/ | 2018-03-13 22:05:58 | 2018-02-07 13:49:07 |
| 39 | http://examplesite2.com/   | 2018-03-13 22:05:35 | 2018-02-13 15:59:39 |

...
+---------+--------------------------------------------+---------------------+---------------------+

This is helpful! I found the site I was looking for, 38, sitetotransfer.com. So, I know that I want to get all of the wp_38_ tables. Turns out WP-CLI is a great way to do this.

wp db export --tables=$(wp db tables 'wp_38*' --format=csv)

This is telling WP-CLI to do a database export, but not the entire database (which would contain all of the tables for the entire network) but rather just the tables starting with wp_38*. The command within the $() is another WP-CLI command which just provides a comma-delimited list of all of the tables starting with wp_38. This will export all of those tables, and save it in a file with a name like site_79ae8bf.sql. If you look at it, you’ll see that it includes something like this:


--
-- Table structure for table `wp_38_commentmeta`
--

DROP TABLE IF EXISTS `wp_38_commentmeta`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `wp_38_commentmeta` (
`meta_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`comment_id` bigint(20) unsigned NOT NULL DEFAULT '0',
`meta_key` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`meta_value` longtext COLLATE utf8mb4_unicode_ci,
PRIMARY KEY (`meta_id`),
KEY `comment_id` (`comment_id`),
KEY `meta_key` (`meta_key`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

Step 2 – Create our new site

Great! We have all of our Posts, Pages, Comments and Options from our old site. Time to create our new site:

Add site to multisite

Once we’ve done this, we can either get the Site ID by running our wp site list command again or, since we’re already in WordPress, if you click on All Sites and hover over the site, you can get the ID by looking at the URL:

Get WordPress Site ID

The ID for this site is 2.

So, we need to ensure that everything in the old site, which had an ID of 38, needs to point to the new site, with an ID of 2.

Edit our SQL

Fire up your trusty text editor (my choice is VS Code, but we aren’t doing anything fancy here. Open up the SQL file you exported earlier (site_79ae8bf.sql, or something similarly cryptic) and we need to do a few find/replace.

Find: wp_38_
Replace: wp_2_

This will drop all of the tables the new, clean network site had, and replace them with the tables from the source multisite site.

Find: uploads/sites/38/
Replace: uploads/sites/2/

Now, we need to ensure that all of the media that was used on the old site is linked to the new location. That’s what this search does.

Wait…what media?

Indeed. We’ll lose out on all of the uploaded images, videos and documents from the old site unless we copy them over. If you’re familiar with scp, that’s probably the quickest way to get it all over, but here I’ll show Transmit, my sftp client of choice.

In this case, we’re copying all of the contents from /wp-content/uploads/sites/38 into the new network, under /wp-content/uploads/sites/2. This step preserves all of the links that exist in the database, so all of your posts and pages should have the same content and appearance.

Cleaning up, and a few caveats

Now, we just need to go into the multisite network’s Sites page:

and edit our new site to make sure the URL matches the old site. At this point, the site should be transferred!

There are a few things to note here:

  1. Users and Plugins do not get transferred over. I’ll write later on how to semi-automate that process, but in the meantime, just ensure that every plugin active on your Source site also exists in your Destination Multisite Network. Transferring the database, as shown above, should automatically activate them.
  2. My site only had three users, so I manually recreated them on the Destination Multisite Network before doing the database transfer. This kept Posts and Pages attributed to the correct people. There are better, automated, ways to do this if you have more users. I’ll write about that later.
  3. You’ll need to point your domain to the new server, using Cpanel, Virtualmin, or however your servers are set up.

Was this helpful?  Let us know!  Need some help?  Contact Us and we can help with your multisite needs!