Home Insights Automated WordPress Installation With Bash & WP CLI
26th November 2014 in Web Development

Automated WordPress Installation With Bash & WP CLI

Louise Towler

By Louise Towler

Automated WordPress Installation With Bash & WP CLI

Like most developers, we tend to start all our WordPress sites the same way. Add various plugins, install a starter theme, create pages and update various options. It’s rarely any different.

After manually installing & configuring WordPress for the 5th time in a week I decided that was it. I needed a better, less time consuming method that required little effort on my part. So I started working on an automated installation bash script to automate the entire process. It’s written for Mac, but may work on Linux (and if you’re using Linux you probably know how to do this anyway). It won’t work on Windows, so sell it and buy a Mac. You’ll also need to install WP CLI. You can find an installation guide on their website.

#!/bin/bash -e

wpuser='exampleuser'

clear

echo "================================================================="
echo "Awesome WordPress Installer!!"
echo "================================================================="

# accept user input for the databse name
echo "Database Name: "
read -e dbname

# accept the name of our website
echo "Site Name: "
read -e sitename

# add a simple yes/no confirmation before we proceed
echo "Run Install? (y/n)"
read -e run

# if the user didn't say no, then go ahead an install
if [ "$run" == n ] ; then
exit
else

# download the WordPress core files
wp core download

# create the wp-config file
wp core config --dbname=$dbname --dbuser=root --dbpass=root

# parse the current directory name
currentdirectory=${PWD##*/}

# generate random 12 character password
password=$(LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 12)

# create database, and install WordPress
wp db create
wp core install --url="http://localhost/$currentdirectory" --title="$sitename" --admin_user="$wpuser" --admin_password="$password" --admin_email="user@example.org"

# install the _s theme
wp theme install https://github.com/Automattic/_s/archive/master.zip --activate

clear

echo "================================================================="
echo "Installation is complete. Your username/password is listed below."
echo ""
echo "Username: $wpuser"
echo "Password: $password"
echo ""
echo "================================================================="

fi

Save this as a .sh file somewhere on your machine such as ~/Scripts/wpinstall.sh, then add an alias to this within your ~/.bash_profile and you’re good to go. I use the alias wpinstall, but you can of course use anything you like.

alias wpinstall="~/Scripts/wpinstall.sh"

Either source your ~/.bash_profile file or re-open terminal and try running wpinstall in an empty directory.

Taking It Further

The script above is a stripped down version of the current script I’m running for our projects. This was generally just to leave you with a script that installs WordPress without the added “awesomeness” that you’ll find below.

A couple of things to note before blindly copying and pasting the script below. I’ve updated my ~/.wp-cli/config.yml configuration file with the following code to add support for mod_rewrite:

apache_modules:
  - mod_rewrite

I’m building the majority of sites using MAMP, and expecting the URL format to match the directory name when prepended with http://localhost/. For example, if I run wpinstall when in the /Applications/MAMP/htdocs/newproject directory, I would expect the website URL to be http://localhost/newproject.

If you run into trouble getting WP CLI working with MAMP (as out of the box, it won’t work), then checkout my previous article: getting WP CLI working with MAMP.

This is my full installation script:

#!/bin/bash -e

wpuser='exampleuser'

clear

echo "================================================================="
echo "Awesome WordPress Installer!!"
echo "================================================================="

# accept user input for the databse name
echo "Database Name: "
read -e dbname

# accept the name of our website
echo "Site Name: "
read -e sitename

# accept a comma separated list of pages
echo "Add Pages: "
read -e allpages

# add a simple yes/no confirmation before we proceed
echo "Run Install? (y/n)"
read -e run

# if the user didn't say no, then go ahead an install
if [ "$run" == n ] ; then
exit
else

# download the WordPress core files
wp core download

# create the wp-config file with our standard setup
wp core config --dbname=$dbname --dbuser=root --dbpass=root --extra-php <<PHP
define( 'WP_DEBUG', true );
define( 'DISALLOW_FILE_EDIT', true );
PHP

# parse the current directory name
currentdirectory=${PWD##*/}

# generate random 12 character password
password=$(LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 12)

# copy password to clipboard
echo $password | pbcopy

# create database, and install WordPress
wp db create
wp core install --url="http://localhost/$currentdirectory" --title="$sitename" --admin_user="$wpuser" --admin_password="$password" --admin_email="user@example.org"

# discourage search engines
wp option update blog_public 0

# show only 6 posts on an archive page
wp option update posts_per_page 6

# delete sample page, and create homepage
wp post delete $(wp post list --post_type=page --posts_per_page=1 --post_status=publish --pagename="sample-page" --field=ID --format=ids)
wp post create --post_type=page --post_title=Home --post_status=publish --post_author=$(wp user get $wpuser --field=ID --format=ids)

# set homepage as front page
wp option update show_on_front 'page'

# set homepage to be the new page
wp option update page_on_front $(wp post list --post_type=page --post_status=publish --posts_per_page=1 --pagename=home --field=ID --format=ids)

# create all of the pages
export IFS=","
for page in $allpages; do
wp post create --post_type=page --post_status=publish --post_author=$(wp user get $wpuser --field=ID --format=ids) --post_title="$(echo $page | sed -e 's/^ *//' -e 's/ *$//')"
done

# set pretty urls
wp rewrite structure '/%postname%/' --hard
wp rewrite flush --hard

# delete akismet and hello dolly
wp plugin delete akismet
wp plugin delete hello

# install lt-tables plugin
wp plugin install https://github.com/ltconsulting/lt-tables/archive/master.zip --activate

# install antispam plugin
wp plugin install antispam-bee --activate

# install the company starter theme
wp theme install ~/Documents/lt-theme.zip --activate

clear

# create a navigation bar
wp menu create "Main Navigation"

# add pages to navigation
export IFS=" "
for pageid in $(wp post list --order="ASC" --orderby="date" --post_type=page --post_status=publish --posts_per_page=-1 --field=ID --format=ids); do
wp menu item add-post main-navigation $pageid
done

# assign navigaiton to primary location
wp menu location assign main-navigation primary

clear

echo "================================================================="
echo "Installation is complete. Your username/password is listed below."
echo ""
echo "Username: $wpuser"
echo "Password: $password"
echo ""
echo "================================================================="

# Open the new website with Google Chrome
/usr/bin/open -a "/Applications/Google Chrome.app" "http://localhost/$currentdirectory/wp-login.php"

# Open the project in TextMate
/Applications/TextMate.app/Contents/Resources/mate /Applications/MAMP/htdocs/$currentdirectory/wp-content/themes/lt-theme

fi

And my ~/.bash_profile contains the following aliases:

alias theme="cd ./wp-content/themes/lt-theme"
alias wpinstall="~/Scripts/wpinstall.sh;theme;npm install;grunt dev"
alias wpinstallquick="~/Scripts/wpinstall.sh;theme"

There are a whole load of other commands available to WP CLI that you could use within an automated installation script, or a deployment script, or even just to do mundane tasks. A full list can be found on the wp cli website along with some code examples and usage instructions.

If you find the script useful, or have any ideas on how I can improve it please leave a comment. I’d love to make the installation even faster.

If there’s anyone on Windows that has a similar script, please let me know in the comments and I’ll add a link to it within the article.

Leave A Comment

  1. I really love what you’ve done here. I’ve been trying to learn this stuff for so long and picking through your work is really helpful. I think I am getting the db error that you referenced though.
    Downloading WordPress 4.1.1 (en_US)... Using cached file '/Users/joshsmith01/.wp-cli/cache/core/en_US-4.1.1.tar.gz'... wSuccess: WordPress downloaded. sh: mysql: command not found
    I followed the steps in the links that you provided and I think I’ve set it up according to your directions. I’ll create a gist of my files, though I haven’t changed them much from yours. -Josh

    1. Hi Josh, Thanks for reading! Have you got a link to those gists? What environment are you running this on? It’s possible you don’t have the path to mysql in your $PATH variable.

    2. MAMP 3.1.
      I think a ton of my problems come from having Server.app installed on my machine. For some reason file permissions, postfix issues always come up. I have since uninstalled Server.app and all errors have been resolved.

      I am taking what you did and adding a few lines like my plugins and my starter themes. The WP CLI is pretty awesome. I am trying to download a fresh copy of WP with only one theme, whatever is the latest. Just to save bandwidth, hard drive space and energy deleting something that I’ll never use.

      Do you have any posts or know of any resources for getting the most out of the WP CLI. They have great documentation but hardly any examples.

    3. Sorry, I’ve only read the WP CLI docs. I guess you’ll get out what your imagination can come up with. One of the things we’ve done is created some custom WP CLI commands in our starter theme so we can automate the creation of custom post types, Shortcodes & various others should we need to. Maybe i’ll write a blog post on this?

      If you want to download only WordPress core you may need to setup a repo on Github that contains WordPress but no themes or plugins (maybe someone else has done this). Good luck with your search, I’d be interested if you figure out how to do this 🙂

  2. Super awesome script!
    For development tasks, I work with MAMP, with virtual hosts enabled, and I am planning on completing the script by entering the new site record in the httpd-vhosts.conf and etc/hosts files. Do you have any ideas of how to get it?
    I also think it will be necessary to restart Apache (MAMP) before visiting the site to reflect changes. Is it possible to do that from a script?
    Thanks in advance!

    1. Hey, I’m glad you asked because it’s something I’ve been thinking about myself. You just gave me the push to figure it out.

      You will need to create a sudoers group, or modify an existing group to allow the use of sudo without a password. This is because /etc/hosts requires your sudoers password in order to edit. You can do this by running sudo visudo. Scroll down until you see the following:

      # Same thing without a password
      # %wheel        ALL=(ALL) NOPASSWD: ALL

      You’ll want to uncomment this group, or create a new group with the same format (but without the #). I’m going to create “developers” as my group name:

      # Same thing without a password
      # %wheel        ALL=(ALL) NOPASSWD: ALL
      %developers     ALL=(ALL) NOPASSWD: ALL

      Next you need to create the user group, which you can do with this command:

      sudo dseditgroup -o create developers

      Then you need to assign a user to this group (eg: christophergeary)

      sudo dseditgroup -o edit -a christophergeary -t user developers

      And now your user should have permission to modify the /etc/hosts file without needing a password. Then, to add a new hosts record to this file, you’ll run something similar to below, but obvisouly you would replace the domain name with whatever you need (perhaps have the domain as an option during install?). The command to write to a file is actually echo "some words" > file.txt but because of the permissions on the file, you basically have to run it like this:

      sudo bash -c 'echo "127.0.0.1     dev.website.com" >> /etc/hosts'

      And that’s it for adding to the hosts file. Hopefully it all makes sense, or atleast is getting you on the right track.

      * * * * * *

      Next we can deal with modifying the vhosts file, which is A LOT easier. You should be able to just edit this file without any issues using a very similar command to above.

      echo '<VirtualHost *:80>
          DocumentRoot "/Applications/MAMP/htdocs/dev-website-com"
          ServerName dev.website.com
      </VirtualHost>
      ' >> /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf

      And that’s that.

      * * * * * *

      Lastly we need to restart apache:

      sudo /Applications/MAMP/Library/bin/apachectl stop
      sudo /Applications/MAMP/Library/bin/apachectl start
      

      And that should be everything you need to get this working with some tweaks. If you got any problems just let us know on twitter 🙂 @crgeary or @ltconsulting

    1. Thanks for the update on your script. I like what you’ve done with removing themes, so I’ll be borrowing that for our script 🙂 Nice job with it!

  3. Curious, is it possible to have this tied to a form submission so a user could enter in some data and then on submit have a script like this run to generate a Wordpress website for them automatically without developers being needed? I’m thinking of a client facing SaaS kind of thing. It’s foreign to me but the idea led me here. Great read!!

    1. I see no reason you can’t hook this up to a form. You have a few options really, you could tweak the script and pass through the arguments like this:

      wpinstall --directory="test" --database="test_db"

      Then run that with php’s shell_exec() function. Another option would be to re-write this script entirely with PHP. Most of the hard work is done by WP-CLI anyway (which is PHP).

      Another option would be to have placeholders within your script such as {{dbname}} which you would later string replace before running.

      Also, you’ll need to have WP-CLI installed on the server that you run the script on. I’d be interested to see what you come up with.

  4. Thank you for publishing this. I’m curious to know if it’s possible to do actually configure a plugin with wp-cli in addition to installing and activating. I’m aware that some plugins are coded to work with wp-cli to some degree but that’s not really helpful for just the configuration aspect.

    1. Hi Mark, It really depends on the type of configuration you need to do to the particular plugins. The short answer is yes, but some are more complex than others.

      For example, most plugins will use the wp_options table for their settings, which means you can make use of wp option update ____ to fill it’s value. Some plugins will store 1 value per option field, and others will store an entire array of options into 1 field which will be more complex to update. For these, you may need to create a custom WP CLI command which handles the unique field structure.

      For anything custom, that you cannot natively do with WP CLI you can create custom commands (link above). The best method I have found is to create a “developer” or “setup” plugin that holds the custom commands. You would then use WP CLI to install and activate this plugin, then the rest of your installation script will have access to the custom commands available inside that plugin. Hopefully that makes sense.

      Did you have a particular plugin you wanted to configure?

  5. HI,

    Thank you very much for sunch good tutorial.

    Could you please tell me how wp db create get the database details?

    I have my database server on another server and I need to tell wp-cli the dbhost,dbpass and dbuser so it can me the connection and create the new website DB.

    Do you have to create a wp-cli.local.yml file?

    Any advises will be really appreciated

    1. Hi Fred, wp db create will take the details out of the wp-config.php file. You can create the wp-config.php file using wp core config. Here’s some information on it.

      You can see an example on line 31 of my example in the article, you would just need to provide the --dbhost argument with it too 🙂

    2. So if I understood correctly, wp db create is ONLY to create the wordpress tables inside the specified DB in wp-config.php.

      I misunderstood and tough that wp-cli was capable of create the database itslef..

      Thank you for your reply

      Fred

    3. It creates the database for you too.. You just have to supply the relevant details for the database server so it can create them.

      In your situation, you will likely already have the host name, a valid username & valid password which you can use to connect to your mysql server.. Once connected you will be able to create databases (assuming you have the relevant permissions). WP CLI ultimately does this for you, you supply the host, username & password for your mysql server along with the desired database name, and then run wp db create. It will connect to the server with your details, and then create the database with the name supplied.

      Hopefully that makes sense?

    4. Hi,

      Thank you for your patience.

      Tradionally i create the wp database as follow:

      # From the database sever
      mysql -u superadmin -p
      CREATE DATABASE dummyDB;
      GRANT ALL ON dummyDB.* to 'dummyDB'@'10.14.24.10' IDENTIFIED BY 'verystrongpassword';

      Now, if I understand you correctly, the wp-cli equivalent would be:

      # create wp database
      wp db create --dbhost=10.14.24.xx --dbuser=superadmin --dbpass=verystrongpassword
      # create wp-config.php
      wp core install --url="$wplocation" --title="$sitename" --admin_user="$wpuser" --admin_password="$wpsupass" --admin_email="$email"

      Did I understood that correctly?

    5. Hi, The equivalent would be as follows (untested):

      # setup wp-config.php
      wp core config –-dbhost=10.14.24.xx -–dbuser=superadmin –-dbpass=verystrongpassword --dbname=dummyDB
      
      # create the database using details in wp-config.php
      wp db create
      
      # create wp-config.php
      wp core install –-url="$wplocation" -–title="$sitename" -–admin_user="$wpuser" -–admin_password="$wpsupass" -–admin_email="$email"
    6. This is a copy and past of my script as it is
      [code]
      #!/bin/sh
      #

      #download the WordPress core files
      wp core download –locale=en_GB

      # setup wp-config.php
      wp core config –dbhost=”10.8.21.15:1596″ –dbuser=”sqldbadmin” –dbpass=”xxx” –dbname=”crasyfredDB”

      # create the database using details in wp-config.php
      wp db create

      # create wp-config.php
      wp core install –url=”http://crasyfred.com” –title=”crasyfred” –admin_user=”fredadmin” –admin_password=”CrasyFred16″ –admin_email=”crasyfred@fred.com”
      [/code]

      and I get the following
      [code]
      Downloading WordPress 4.4.2 (en_GB)…
      Using cached file ‘/home/webadmin/.wp-cli/cache/core/wordpress-4.4.2-en_GB.tar.gz’…
      Success: WordPress downloaded.
      mysql: not found
      Error: wp-config.php not found.
      Either create one manually or use `wp core config`.
      Error: wp-config.php not found.
      Either create one manually or use `wp core config`.
      [/code]

      If you have no more time to give me, just say so, don’t worry:)

    7. UPDATE: I didn’t have mariadb client installed on the server 🙁

      I can confirm that the above is 100% working now.

      The only issue that I have is that I had to create the mysql user with GRANT ALL PRIVILEGES which is not very secure..

    8. Good to hear! You could always create the database with SSH, and not with WP CLI.. Just use WP CLI for everything else? 🙂

  6. Hi Christopher,

    I have incorporated bits of you script in my shell script and it all work very well except one thing..
    I haven’t managed to convert the following bash code into shell scripting

    # setup wp-config.php
    wp core config –dbhost=$dbhost –dbuser=$dbuser –dbpass=$dbpass –dbprefix=$dbprefix$prefix –dbname=$dbname <<PHP
    define( 'WP_DEBUG', true );
    define( 'DISALLOW_FILE_EDIT', true );
    define( 'WP_MEMORY_LIMIT', '64M' );
    PHP

    When I run it the 'define' lines are not in the wp-config.php file.

    Can you help?

    Thank you

    1. Hi Fred,

      Sorry for the late response, hopefully you have sorted this now. If not, it looks like you need to include the --extra-php flag. Here is an example, if you look at the end of the first line you should see what I mean 🙂

      wp core config --dbname="$database" --dbuser=root --dbpass=root --extra-php <<PHP
      
      define( 'WP_DEBUG', true );
      define( 'DISALLOW_FILE_EDIT', true );
      define( 'WP_MEMORY_LIMIT', '64M' );
      
      PHP
    2. Yes, I managed to figured it out , such silly mistake.
      COuld you please tell me if there are any website what provide decent trainning/understanding on wp-cli?
      I find it hard to get any good info out there

    3. The documentation (1) is a pretty good place to start, it has a list of all the commands, and the options those commands take.. If you’re running this on Mac/Linux, then perhaps look to learning some basic bash programming as this will improve your ability to write scripts that leverage WP CLI.

      There are also some good videos on WordPress TV (2) you could look at, and smashing magazine has a good article you should read (3).

      Daniel Bachhuber (the man behind WP CLI) is working on a v2 (4), which is worth keeping an eye on. This is in development, but would be useful for you to be aware of as it works a little differently to the current stable version.

      If you have any questions, you’re happy to tweet me @crgeary and I’ll try my best to answer.

      1. http://wp-cli.org/commands/
      2. https://www.smashingmagazine.com/2015/09/wordpress-management-with-wp-cli/
      3. http://wp-cli.org/restful/

  7. Hi Christoher,

    I wanted to thank you for this post. I just used a modified version your bash script and combined with Laravel Valet so that I can now setup local WordPress development environments in a minute or less.

    I made a video here: https://youtu.be/Ai-HogVDxq4

    Thanks again!

    1. Hi Paul,

      Thanks for the mention in the video.

      I haven’t had a chance to checkout Valet myself yet, so thanks for giving me another reason to take a look. Nice work on the tutorial.

  8. Thanks for the post, Chris. Can’t wait to get it working.

    For some reason, whenever I run the script, it’s going through downloading files etc. fine, but then when it gets to creating the database, I’m getting the following errors:

    Warning: mysqli_real_connect(): (HY000/2002): No such file or directory in /Applications/MAMP/htdocs/test/wp-includes/wp-db.php on line 1529
    Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /Applications/MAMP/htdocs/test/wp-includes/wp-db.php on line 1559
    Warning: mysql_connect(): No such file or directory in /Applications/MAMP/htdocs/test/wp-includes/wp-db.php on line 1559
    Fatal error: Call to undefined function wp_die() in /Applications/MAMP/htdocs/test/wp-includes/wp-db.php on line 3160

    Do you know what could be causing this?

    1. Hi Seb,

      This could be to do with the copy of PHP WP CLI is trying to use, or which MySQL instance you’re trying to use.. Mac I believe comes packaged with PHP & MySQL out of the box which WP CLI will try to use automatically. You need to make sure WP CLI is using your MAMP version of PHP & MySQL.

      You can type which php to see which version of PHP your CLI is using. You can also run wp cli info to get information about your WP CLI setup. Your PHP binary should be set to a version from MAMP, you can find out how to do this here: http://wp-cli.org/docs/installing/#using-a-custom-php-binary

      Hopefully this helps, if you have any other issues, please post the results of the above command(s) in with your comment 🙂

    2. Hi,
      I have the same issue. The strange thing is that when I run the wp core install command manually from the Terminal it works. But it does not work if I put this command into a script, and run the script.
      I compared the outputs of which php, which mysql and wp cli info from the Terminal and from the script, and I get the same results. It’s using the PHp and MySQL from MAMP.
      Any ideas ?
      thanks

    3. Hi Maxime,

      As this works from Terminal, but not from a script, it may be an issue with .bash_profile and .bashrc. Which one is used differs depending on whether you run code from an interactive shell or non-interactive shell, so it’s possible aliases/exports you have in one are not available in the other.

      Sorry if I could not be of more help 🙂

  9. As of Windows 10 – Anniversary Update, Bash is now fully available for all version. So I do believe a separate Windows script is no longer necessary and your post can be updated to say it should also work on Windows if you have bash enabled. I think, totally untested! 🙂

  10. Great script and great explanation. It really helps when you need a fast spin without vagrants or things like that.
    As for windows 7 users without the bash that win10 offers i created this gist

    Its a stripped down and doesnt ask much aside database name and full url but it might be a good point to start

  11. Thanks – this is awesome! My script is ready, and I can’t wait for my next project – as the current one was still constructing the script as I go and learning the ropes and not fully automated yet. Next project is expected to fly like a rocket. Thanks again! 🙂

  12. Nice job!!

    I’ve spent the last several months trying to automate installation of multiple stores using bash, wp-cli, woocommerce and storefront theme. I’ve got mostly everything working – the portion on deleting and adding pages was instrumental.

    Now I’m stuck on how to automate the woocommerce setup wizard functions so that shop, cart, etc. pages get created, and whatever other details the setup wizard normally takes care of. Any ideas? As a last resort I’m thinking to just call the setup wizard directly from my bash script, but what I’m afraid of is missing something important that gets done either before or after setup. Thank you!

    1. Thank you!

      I’m not sure what the WooCommerce wizard does for you, but that would be your first step. If you can figure out what it is doing, or what code it runs, you can either replicate with WP CLI or maybe create your own WP CLI commands that call those relevant WooCommerce functions.

      Another option would be to use Headless Chrome, or PhantomJS to automate in the browser.

      Good luck with your script 🙂

  13. Hello everyone I am new here,
    I wish to carry out this automated installation immediately a hosting account is created I have a few questions that will help me achieve my goals.

    (1) Where do I deploy the script as in which directory do I upload the script so that it runs once the account is created?
    (2) I have my custom designed wordpress site at what point do I define this content so that after the script runs a complete site with content is issued to the user.

    1. Hi Wanjala,

      1) This depends entirely on your hosting provider. The script can be placed anywhere on the server, it will install WordPress in the directory that the script is run.

      2) I’m not sure I completely understand what you’re trying to archive.

      I suspect the script (as it is now) is not directly useful to you. You will likely want to write you own, and use ours as a reference point. The script above is specifically designed to install a blank copy of WordPress with some options & our blank starter theme. It doesn’t work with existing sites.

      I would do the process manually, and write a detailed step by step guide listing *everything* that you did. You can then convert each step into a command that you can use to automate the process. Checkout the docs for WP CLI for more examples of commands, and of course, our script above for further examples.

Leave a Reply

Your email address will not be published. Required fields are marked *