Monday, June 22, 2015

Wordpress multisite migration with wp-cli

There are many way to migrate a multisite WordPress to a new one including: database import... In my case:


  1. I created new blogs for all the users first (in the new multisite, the blog_ids will be different than in the old multisite).
  2. Export data of all blogs (wordpress-importer) from the old multisite. (wp-cli)
  3. Import data (only posts, comments) exported from the old blogs. (wp-cli)
  4. Finally, copy over the media, rename the directory names with the new blog_id. Search and replace all the media links in the database (wp-cli)

Here are the details steps:

1. Export data of all the blogs from the old WordPress multisite and transfer to the new one:

We need to use my modification of wp-cli (click here) to set name of the backup data the blog's path: blog1path.xml, blog2path.xml... This way we will know which file belongs to which blog and user in the new multisite.

Assuming:

  • My custom wp-cli source is at /home/myuser/wp-cli/
  • Wordpress multisite root: /var/www/
  • Backup files will be stored at: /home/myuser/export/ in both multisite instances.
  • New multisite server's domain is: new.multisite.com

* On the old multisite, create a shellscript:


$ nano export_network.sh

#! /bin/bash
for url in $(/home/myuser/wp-cli/bin/wp site list --path=/var/www --field=url)
do
        echo $url
        /home/myuser/wp-cli/bin/wp export --path=/var/www --dir=/home/myuser/export/ --url=$url
done

* Run it:

$ sudo chmod +x export_network.sh
$ ./export_network.sh

* Transfer all the backup to the new multisite server

$ rsync -arv /home/myuser/export/ myuser@new.multisite.com:/home/myuser/export/


2. Import the backup data to the new WordPress multisite:
(we don't need to use my version of wp-cli to do this task)

We will import the backup data to the new blogs based on their path (blog1path.xml, blog2path.xml... they're the same in both multisite, that's why we used my modified version of wp-cli)

Assuming:

  • Exported data is stored at: /home/myuser/export/
  • New multisite wordpress root: /var/www/
  • We have a mapping file at /home/myuser/mapping.csv for the user_logins (they are the same in both multisite):
old_user_login,new_user_login
user1,user1
user2,user2
....


* On the new multisite, create a shellscript:

$ nano import_network.sh

#! /bin/bash

for mypath in $(wp site list --path=/var/www --field=path)
do
        tmppath="${mypath////""}"
        myfile="/home/myuser/export/$tmppath.xml"
        if [ -f "$myfile" ]
        then
                echo "* Importing $myfile."
                url="http://new.multisite.com$mypath"
                wp import $myfile --path=/var/www --authors=/home/myuser/mapping.csv --url=$url --skip-themes
        fi
done

* Run it:

$ sudo chmod +x import_network.sh
$ ./import_network.sh


Then all the posts and comments will be in place.

3. The next thing we need to do is to transfer all the medias to the new server:

a. On the old server: I don't want to migrate a whole server so I use this method to transfer media folders of a number of blogs only:

  • Prepare a blog_ids.csv file which contains blog ids you want to transfer:

1234
2345
....

  • Install sshpass to assign ssh password for rsync command:


$ sudo apt-get install sshpass


  • Create and run the copy script:


$ nano copy_to_new.sh

#! /bin/bash

for oldblogid in `cat $1`
do
        media=/var/www/wp-content/blogs.dir/$oldblogid  
        echo "=== Checking the existance of $media directory..."                                                                                       
        if [ -d "$media" ] 
        then
                echo "    Existed! Copying $media..."                                                                                                  
                sshpass -p 'your-ssh-password-for-myuser' rsync -arv $media -e ssh myuser@new.multisite.com:/home/myuser/sites/               
        fi
done

$ chmod +x copy_to_new.sh
$ ./copy_to_new.sh blog_ids.csv


b. The media folders are named after the blog ids they belong, so In the new server, rename the folders with the new blog ids:

  • Prepare the (old_blog_id,new_blog_id) mapping file (without header):
1234,345345
2345,35356
...
  • Assuming we have these 3 folders:
    • /home/myuser/sites: contains old the media folders transferred from the old server
    • /home/myuser/tmp: temporary folder to rename old media folders.
    • /home/myuser/new: renamed media folders.
  • Use the following script to rename media folders:
$ nano rename_media.sh


#! /bin/bash

IFS=','
while read f1 f2
do
        old=/home/myuser/sites/$f2
        echo "=== Checking existance of $old ..."
        if [ -d "$old" ]
        then
                echo "    Copying $old to /home/myuser/tmp/ ..."
                tmp=/home/myuser/tmp/$f2
                cp -R $old $tmp
                new=/home/myuser/new/$f1
                echo "    Moving and rename $tmp to $new ..."
                mv $tmp $new
        fi
done < $1


  • Move the renamed media folders to wordpress root:
$ sudo rsync -arv /home/myuser/new/ /var/www/wp-content/uploads/sites/
$ sudo chown www-data:www-data /var/www/wp-content/uploads/sites -R



4. Search and Replace media url string in the database:

Assuming:
  • old domain media path: http://old.multisite.com/<blog path>/files/
  • new domain media path: http://new.multisite.com/<blog path>/wp-content/uploads/sites/<blog id>/
  • Prepare a mapping csv file (blog_mapping.csv) as following:
new_blog_id,path
678,myblogpath
679,mysecondpath
...

+ Create and run the following script on the new server:

$ nano search_replace_network.sh

#! /bin/bash

IFS=','
while read f1 f2
do
        # remove the carriage return character at the end of each line (path column)
        path=$(echo $f2 | sed -e 's/\r//g')
        old="http://old.multisite.com/$path/files/"
        new="http://new.multisite.com/$path/wp-content/uploads/sites/$f1/"
        url="http://new.multisite.com/$path/"
        wp search-replace $old $new --path=/var/www --url=$url --allow-root
done < $1

$ sudo chmod +x search_replace_network.sh
$ ./search_replace_network.sh blog_mapping.csv


Cool!!! \m/