After we had upgraded a website from development to production status, we will need to put up a maintenance notice if we are required to make further changes. It is unpleasant to let visitors see the down-time or on-going changes and is bad for SEO if we made erroneous changes to the layout or contents of our live website. The common solution is to setup a ‘demo’ website which is a replica of the live website. This way, we can install/ uninstall plugins or change layout/ contents without affecting the live website for visitors. Let’s say we had installed many plugins, changed the layout drastically, made changes to theme files etc. on the demo website. Then how do we revert back to the looks of the live website for another session of testing on another day? This tutorial will show you how to write a simple bash script to automate the syncing of live WordPress files and database to demo in crontab.
This bash script is related to WordPress directory and database but with slight modification, it can be deployed for other purposes.
- WordPress with Docker
- MySQL username and password for WordPress database.
- Access to root crontab because WordPress directories under www-data:www-data
Step 1 – Paste this Bash Script to Server
#!/bin/sh echo Delete Demo directories and sync Live to Demo (except wp-config.php) find /home/user/wp-docker/wordpress-DEMO -mindepth 1 -type f,d ! -name 'wp-config.php' -delete rsync -avq --exclude 'wp-config.php' /home/devcube/wp-docker/wordpress-LIVE/ /home/user/wp-docker/wordpress-DEMO/ echo Drop and create Demo database before restore Live to Demo database docker exec db mysql -udbuser -p'dbpwd' -e "DROP DATABASE wordpress_demo; CREATE DATABASE wordpress_demo;" docker exec db mysqldump -udbuser -p'dbpwd' wordpress_live | docker exec -i db /usr/bin/mysql -udbuser -p'dbpwd' wordpress_demo echo Update Live to Demo domain name in Demo database docker exec db mysql -udbuser -p'dbpwd' -e "USE wordpress_demo; UPDATE wp_comments SET comment_content = replace(comment_content , 'example.com','demo.example.com');" docker exec db mysql -udbuser -p'dbpwd' -e "USE wordpress_demo; UPDATE wp_links SET link_url = replace(link_url, 'example.com','demo.example.com');" docker exec db mysql -udbuser -p'dbpwd' -e "USE wordpress_demo; UPDATE wp_options SET option_value = replace(option_value, 'example.com', 'demo.example.com') WHERE option_name = 'home' OR option_name = 'siteurl';" docker exec db mysql -udbuser -p'dbpwd' -e "USE wordpress_demo; UPDATE wp_postmeta SET meta_value = replace(meta_value,'example.com','demo.example.com');" docker exec db mysql -udbuser -p'dbpwd' -e "USE wordpress_demo; UPDATE wp_posts SET post_content = replace(post_content, 'example.com', 'demo.example.com');" docker exec db mysql -udbuser -p'dbpwd' -e "USE wordpress_demo; UPDATE wp_posts SET guid = replace(guid, 'example.com','demo.example.com');" docker exec db mysql -udbuser -p'dbpwd' -e "USE wordpress_demo; UPDATE wp_usermeta SET meta_value = replace(meta_value, 'example.com','demo.example.com');"
- Delete files and directories in demo directory except wp-config.php because we want this line define( ‘DB_NAME’, ‘wordpress_demo’); to remain unchanged. Also, we do not delete the parent directory hence -mindepth 1 or else we will get this error find: cannot delete ‘/home/user/wp-docker/wordpress-DEMO’: Directory not empty
- Rsync all contents of WordPress live directory to demo except wp-config.php.
- Drop and create WordPress demo database.
- Dump live database and restore to demo database.
- Search and replace live with demo domain name in demo database.
Step 2 – Add Bash Script to Crontab
We will need to prepare an empty log file before adding the bash script to root crontab with touch /home/user/cronjobs/wpLive-to-wpDemo.log
# Reload Live WP to Demo WP at 3am daily 0 3 * * * /usr/bin/sh /home/user/cronjobs/wpLive-to-wpDemo.sh >> /home/user/cronjobs/wpLive-to-wpDemo.log 2>&1
Step 3 – (optional reading) Pitfalls
There are a couple of dos and don’ts that were discovered when creating the bash script in Step 1.
rm -Rf /home/user/wp-docker/live cp -Rf /home/user/wp-docker/live /home/user/wp-docker/demo
// ** MySQL settings - You can get this info from your web host ** // /** The name of the database for WordPress */ define( 'DB_NAME', 'wordpress_live');
We cannot delete the entire WordPress demo directory and copy the live one over. This is because Docker mounted the demo directory as a volume and this will cause Apache Forbidden error. To resolve this, we will have to execute docker-compose down and docker-compose up -d. Furthermore, this will copy the live wp-config.php over to demo directory which will cause all the live links (example.com) to appear in demo website instead of (demo.example.com) because it is uses the WordPress live database.
docker exec db mysql -udbuser -p'dbpwd' wordpress_demo < /home/user/backups/wordpress_live.sql docker exec db mysqldump -udbuser -p'dbpwd' --add-drop-database wordpress_live | docker exec db mysql -udbuser -p'dbpwd' wordpress_demo cat /home/user/backups/wordpress_live.sql | docker exec db mysql -udbuser -p'dbpwd' wordpress_demo
All three docker exec commands above will not work because we need to include -i which according to Docker docs means keep STDIN open even if not attached. In my own words, I think it means to keep the standard input stream open to read in data which in our case, is the MySQL database for restoration.
cat /home/user/backups/wordpress_live.sql | docker exec -i db /usr/bin/mysql -udbuser -p'dbpwd' wordpress_demo docker exec db mysqldump -uroot -p'dbpwd' wordpress_live | docker exec -i db /usr/bin/mysql -udbuser -p'dbpwd' wordpress_demo
Both docker commands above will work now. Which one to use depends if we are trying to restore from a backup sql file or from a direct mysqldump from live to demo database.
docker exec db mysql -udbuser -p'dbpwd' -e "USE wordpress_demo; UPDATE wp_options SET option_value = 'MyBlog DEMO' WHERE option_name = 'blogname';"
This is an optional SQL UPDATE to differentiate the demo from live WordPress website by changing the site name to e.g. MyBlog DEMO but if you are using a site logo like TechSch.com, then this is not required.
So, here we have it – a bash script that will automate the mirroring of the live website (example.com) to the demo website (demo.example.com) on a daily basis. Whatever plugins, themes or updated version of WordPress on the live website will all be sync to the demo site. This allows us to experiment with all sorts of stuffs on demo website even to the extent of breaking it without worries. Once we are satisfied with all the testing, we can safely apply it to the live website without bringing it down. And the wonderful thing is that when you wake up the next day, the demo website will be reloaded just like the live one for you to conduct another round of testing!