WordCamp Phoenix 2013

WP 401:
Develop, Stage, Deploy

Paul Clark
WordCamp Phoenix 2013

pdclark on twitter, wordpress.org

About Me


Technical Director at Brainstorm Media


But whyyyyy!??!?!

Reasons for a Local Dev Environment

Reasons for a Staging Environment

Challenges & Solutions

Setting up a server is hard!

Use a packaged server.

Challenges & Solutions

Changing the domain breaks things!

You have options:

* Text you want to find on the left, replacement on the right.
* That's it! Load this script in a browser to run it.
$find_replace = array(
	// 'OldText' => 'NewText',
	'' => '',

Or... test with the real domain name

Use the hosts file.
# Mac/Linux: /etc/hosts
#     Copy to Desktop, edit, copy back. (Or use sudo.)
# Windows: C:\WINDOWS\system32\drivers\etc\hosts 
#     Open NotePad as Administrator)

# Point site.com to your computer site.com

# Point site.com to the same server as wordpress.com site.com

Use Chrome or Firefox plugins to quicky see a site's IP address
or flush your DNS cache.

Challenges & Solutions

How do I sync files?

Command line: rsync

# -a: Archive. Recursive. Keep permissions, symlinks, & timestamps
# -v: Verbose
# -z: Compress files before transferring
# Copy all modified files from remote to local working directory
rsync -avz -e ssh --progress user@remote.com:/public_html/. ./
# Local to remote: Just swap the order
# Note: ./. means "All files in the current directory,
#                  including those starting with a dot"
rsync -avz -e ssh --progress ./. user@remote.com:/public_html/

Command line: wget

Download only
# Copy remote files to local over FTP
# http://stackoverflow.com/questions/113886/how-do-you-recursively-ftp-a-folder-in-linux
# -nH avoids the creation of a directory named after the server name
# -nc avoids creating a new file if it already exists on the destination (it is just skipped)
# --cut-dirs=5 take the content of /absolute/path/to/directory and to put it in the directory where I launch wget. The number 5 is used to filter out the 5 components of the path. The double slash means an extra component.
# -l 30 Recurse 30 directory levels deep

# cd into wp-content
cd site.com/public_html/wp-content

# Download changed files recursively using FTP
wget -r -l 30 -nH --cut-dirs=3 -N ftp://username:password@site.com//public_html/wp-content

Command line: Deployment Scripts

Challenges & Solutions

How do I get the database?!

What about wp-config?

Split into wp-config-live.php and wp-config-dev.php, or do this:
// $is_local check option 1: Both visitor and server are localhost
$is_local = ( '' == $_SERVER['SERVER_ADDR'] 
              && '' == $_SERVER['REMOTE_ADDR'] );

// $is_local option 2: Path check          Any Mac user dir --v
$is_local = ( false !== strpos($_SERVER['DOCUMENT_ROOT'], '/Users/') );
// Choose database credentials based on server environment
if ( $is_local ) {
    // Development
    define( 'DB_NAME',     'dev_db_name' );
    define( 'DB_USER',     'dev_user' );
    define( 'DB_PASSWORD', 'dev_password' );
} else {
    // Live
    define( 'DB_NAME', 'live_db_name' );
    define( 'DB_USER', 'live_db_user' );
    define( 'DB_PASSWORD', 'live_password' );

PHPMyAdmin is Slow!

Have SSH access? Use the command line.

# Export a database to db.sql
# Leave PASSWORD blank to enter at prompt (safer)
# Note: No space between -p and PASSWORD
mysqldump --add-drop-table -u user_name -pPASSWORD db_name > db.sql

# Import a database into MySQL
mysql db_name -u user_name -pPASSWORD < db.sql

I can't remember my MySQL credentials!

Good! You shouldn't be able to!

# Put this in ~/.my.cnf
user = mysql_username
password = mysql_password
host = mysql_host_if_not_localhost
# Then chmod it (make the file only readable by your user)
chmod 600 ~/.my.cnf
# Now you don't need credentials

# Export a database to db.sql
mysqldump --add-drop-table database_name > db.sql

# Import a database into MySQL
mysql database_name < db.sql

That's better... I want faster

One liners: remote to local and visa-versa.
# Export remote database directly to local database
# Add -u and -p options if you haven't set up ~/.my.cnf on both
ssh user@site.com "mysqldump --add-drop-table db_name" | mysql db_name

# Export local database directly to remote database
# Add -u and -p options if you haven't set up ~/.my.cnf on both
mysqldump --add-drop-table db_name | ssh user@site.com "mysql db_name" 

I don't want to remember SSH credentials

Set up a server alias
# Put this in local ~/.ssh/config
# Your alias for this account. Separate several with spaces.
Host site
User my_username
# IP address or domain name
# Alternate port if not 22. (e.g., HostGator uses 2222)
# Port 22
And copy your public key to remote
# Same thing as copying the contents of local id_rsa.pub
# to the end of remote ~/.ssh/authorized_keys
scp ~/.ssh/id_rsa.pub user@remote.site.com:/tmp/id_rsa.pub
ssh user@remote.site.com "mkdir -p ~/.ssh;chmod 700 ~/.ssh;touch ~/.ssh/authorized_keys;cat /tmp/id_rsa.pub >> ~/.ssh/authorized_keys"

Go fast, remember nothing

With .my.cnf, .ssh/config, and authorized_keys set up:
# Copy remote database to local
ssh site "mysqldump --add-drop-table db_name" | mysql db_name

# Copy local database to remote
mysqldump --add-drop-table db_name | ssh site "mysql db_name" 
With naming conventions
# For site.com, if you always name your ssh aliases and database after the domain

# Copy remote database to local
ssh site "mysqldump --add-drop-table site" | mysql site

Thank you! (Questions?)

Slides online at