Switching primary site in WordPress Multisite

Four years old and no answer? So here we go…-

Let’s take the following network setup as example (I’m using WP-CLI’s site list command):

$ wp site list
+---------+--------------------+---------------------+---------------------+
| blog_id | url                | last_updated        | registered          |
+---------+--------------------+---------------------+---------------------+
| 1       | http://wp.tmp/     | 2016-08-04 08:39:35 | 2016-07-22 09:25:42 |
| 2       | http://foo.wp.tmp/ | 2016-07-22 09:28:16 | 2016-07-22 09:28:16 |
+---------+--------------------+---------------------+---------------------+

The network site list would look like this:

network site list

We want to use the site with ID 2 as the new root site with the URL http://wp.tmp/. This is actually the same problem as described in the question just with some other values for the ID and the URLs.

The multisite relevant part of the wp-config.php looks probably like this:

const MULTISITE            = TRUE;
const DOMAIN_CURRENT_SITE  = 'wp.tmp';
const PATH_CURRENT_SITE    = "https://wordpress.stackexchange.com/";
const SITE_ID_CURRENT_SITE = 1;
const BLOG_ID_CURRENT_SITE = 1;
const SUBDOMAIN_INSTALL    = TRUE;

Updating database site settings

WordPress uses the tables wp_*_option and wp_blogs to find the matching blog for a given request URL and to build proper permalinks for this blog. So we have to change the values in the following three tables (for this example):

  • In wp_options the keys home and siteurl
  • In wp_2_options the keys home and siteurl (in your case this would be wp_15_options)
  • In wp_blogs the column domain for both sites with ID 1 and 2 (respectively 15)

I’m using Adminer for this, but any other DB management tool (PhpMyAdmin) does the job as well. (The screenshots shows the GUI in German language but I guess the idea is clear.)

adminer edit wp_options

In wp_options (the options table for site ID 1) I changed the values of both keys home and siteurl from http://wp.tmp to http://foo.wp.tmp. (The screenshot above shows the state before the update.)

I did exactly the same with the table wp_2_options but here I changed the value from http://foo.wp.tmp to http://wp.tmp.

Next step is to update the table wp_blogs:

adminer edit wp_blogs
(Again, the screenshot shows the table before I made any change.) Here you simply switch the values from both sites in the domain column:

  • wp.tmp becomes foo.wp.tmp and
  • foo.wp.tmp becomes wp.tmp

Now you have to update the wp-config.php to deal correctly with the new settings data:

const MULTISITE            = TRUE;
const DOMAIN_CURRENT_SITE  = 'wp.tmp';
const PATH_CURRENT_SITE    = "https://wordpress.stackexchange.com/";
const SITE_ID_CURRENT_SITE = 1;
const BLOG_ID_CURRENT_SITE = 2; // This is the new root site ID
const SUBDOMAIN_INSTALL    = TRUE;

At this point you have again a working WordPress multisite but with a new root site:

$ wp site list
+---------+--------------------+---------------------+---------------------+
| blog_id | url                | last_updated        | registered          |
+---------+--------------------+---------------------+---------------------+
| 1       | http://foo.wp.tmp/ | 2016-08-04 08:39:35 | 2016-07-22 09:25:42 |
| 2       | http://wp.tmp/     | 2016-07-22 09:28:16 | 2016-07-22 09:28:16 |
+---------+--------------------+---------------------+---------------------+

network site list updated

Remember: during this process, your site will be not available and requests will end up in some nasty errors so you might want to arrange a 503 Service Unavailable response in front of your WordPress installation. This could be done using .htaccess.

Updating database content

Now comes the tricky part. At the moment, all URLs in the content tables are still pointing to the resources of the old sites. But replacing them is not that easy: Replacing every http://foo.wp.tmp with http://wp.tmp in the first step and every http://wp.tmp with http://foo.wp.tmp in the next step will end up in having all former URLs pointing to site ID 1 (http://foo.wp.tmp).

The best way would be to insert an intermediate step:

  • Search for http://foo.wp.tmp and replace it with a preferably unique slug: http://3a4b522a.wp.tmp
  • Search for http://wp.tmp and replace it with http://foo.wp.tmp
  • Search for http://3a4b522a.wp.tmp and replace it with http://wp.tmp

All these search and replace commands should ignore the three tables (*_options *_blogs) we updated before, otherwise they would break the configuration. You might also have a manual look for URLs in wp_*_options table outside of the home and siteurl keys.

I would suggest to use WP-CLI’s search-replace command for this as it can deal with serialized data and has no limitations that HTTP might have.

Leave a Comment