Leveraging WP-CLI Aliases in Your WordPress Development Workflow

Thanks for trying out aliases!

This should probably be moved to a support thread rather than discussion of the post.

You can include your questions there, and additionally please include information about where you are running the script to provide more context.

Consider separating out #4 as another thread as it’s own can of worms.

Nice post Raquelle! Aliases are awesome.

I found you can remove the need for the sql-dump-development.sql file and run it in one go like this from the environment you want to run the import on:

wp @remote db export - | wp db import -

This won’t be as practical for large databases where you might need to compress it to get a reasonable transfer time, but it makes for a nice one-liner :ok_hand:

3 Likes

Hold on … you’re telling me we can duplicate WP Migrate DB Pro with just a shell script?

4 Likes

Just getting round to trying this now and I can certainly see a lot of value in this.

On a Trellis + Bedrock set up, I can get staging and prod aliases working fine but I’m having trouble with development.

@development:
  ssh: vagrant@example.dev/srv/www/example.com/current

Fairly new to Trellis but this gives me:

Error: Cannot connect over SSH using provided configuration.

And if I manually try:

vagrant@example.dev

I get:

Permission denied (publickey).

Maybe I’m totally missing something or maybe the Trellis setup has changed since this post?

Edit

OK, got it figured out. I wasn’t sure as the post referenced Trellis and Vagrant separately, so I tried the Vagrant part of the post, running the following in the Trellis directory:

$ vagrant ssh-config --host example.dev >> ~/.ssh/config

This then let the SSH connection work. Probably my bad for not realising this needed to be done first.

3 Likes

I made a script to auto-update my local SSH config on vagrant up to make sure that the port always works. I noticed that after rebooting or having different Vagrant boxes running that my SSH attempts would fail.

Add the following to your Vagrantfile within the VM provisioner (config.vm.provision provisioner do |ansible|)

    # Run script to update local SSH config for .dev hostname after `vagrant up`
    if Vagrant.has_plugin?('vagrant-triggers')
      config.trigger.after :up do
        run "./bin/ssh-config-development.sh"
      end
    else
      fail_with_message "vagrant-triggers missing, please install the plugin with this command:\nvagrant plugin install vagrant-triggers"
    end

Then create bin/ssh-config-development.sh with the following:

host="example.dev"
sed "/^$/d;s/Host /$NL&/" ~/.ssh/config | sed '/^Host '"$host"'$/,/^$/d;' > config &&
cat config > ~/.ssh/config &&
rm config &&
vagrant ssh-config --host example.dev >> ~/.ssh/config
8 Likes

Also, here’s the latest version of the sync script I’ve been using that lives at site/scripts/sync.sh

#!/bin/sh

DEVDIR="web/app/uploads/"
DEVSITE="https://example.dev"

PRODDIR="web@example.com:/srv/www/example.com/shared/uploads/"
PRODSITE="https://example.com"

STAGDIR="web@staging.example.com:/srv/www/example.com/shared/uploads/"
STAGSITE="https://staging.example.com"

FROM=$1
TO=$2

case "$1-$2" in
  development-production) DIR="up";  FROMSITE=$DEVSITE;  FROMDIR=$DEVDIR;  TOSITE=$PRODSITE; TODIR=$PRODDIR; ;;
  development-staging)    DIR="up"   FROMSITE=$DEVSITE;  FROMDIR=$DEVDIR;  TOSITE=$STAGSITE; TODIR=$STAGDIR; ;;
  production-development) DIR="down" FROMSITE=$PRODSITE; FROMDIR=$PRODDIR; TOSITE=$DEVSITE;  TODIR=$DEVDIR; ;;
  staging-development)    DIR="down" FROMSITE=$STAGSITE; FROMDIR=$STAGDIR; TOSITE=$DEVSITE;  TODIR=$DEVDIR; ;;
  *) echo "usage: $0 development production | development staging | production development | production staging" && exit 1 ;;
esac

read -r -p "Would you really like to reset the $TO database and sync $DIR from $FROM? [y/N] " response

if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
  cd ../ &&
  wp "@$TO" db export &&
  wp "@$FROM" db export - | wp "@$TO" db import - &&
  wp "@$TO" search-replace "$FROMSITE" "$TOSITE" &&
  rsync -az --progress "$FROMDIR" "$TODIR"
fi

Usage:

$ ./sync.sh
usage: ./sync.sh development production | development staging | production development | production staging

eg.

$ ./sync.sh development production
$ ./sync.sh production development
13 Likes

@ben that looks great. I had already tweaked around with your last script but that’s a whole let better than what I had put together. Just gave this a test run and worked perfectly.

Question: I had added to mine the removal of the resulting .sql files. It looks like in this script we get left with a single .sql file on the remote server. Should this be removed after import?

I left it as a way of leaving a backup incase you didn’t mean to push up a new DB, but have considered moving that to a more temporary area. Feel free to remove/tweak :slight_smile:

Makes sense, appreciate the reply :slight_smile:

WP-CLI supports a global config file! Per the docs you can have a global config in ~/.wp-cli/config.yml - I just set it up with aliases, and now I can use my aliases from any folder :grin:

1 Like

I just noticed the last case doesn’t match up with the last usage example - I added in production <> staging and updated the usage text. I also made the site URLs root relative, just for compatibility reasons.

The first case also has ; after DIR="up" whereas the others don’t; I added to make consistent though I’m not sure it actually matters since each statement is just a variable declaration.

#!/bin/sh

DEVDIR="web/app/uploads/"
DEVSITE="//example.dev"

PRODDIR="web@example.com:/srv/www/example.com/shared/uploads/"
PRODSITE="//example.com"

STAGDIR="web@staging.example.com:/srv/www/example.com/shared/uploads/"
STAGSITE="//staging.example.com"

FROM=$1
TO=$2

case "$1-$2" in
  development-production) DIR="up";  FROMSITE=$DEVSITE;  FROMDIR=$DEVDIR;  TOSITE=$PRODSITE; TODIR=$PRODDIR; ;;
  development-staging)    DIR="up";   FROMSITE=$DEVSITE;  FROMDIR=$DEVDIR;  TOSITE=$STAGSITE; TODIR=$STAGDIR; ;;
  production-development) DIR="down"; FROMSITE=$PRODSITE; FROMDIR=$PRODDIR; TOSITE=$DEVSITE;  TODIR=$DEVDIR; ;;
  production-staging)     DIR="horizontally"; FROMSITE=$PRODSITE; FROMDIR=$PRODDIR; TOSITE=$STAGSITE; TODIR=$STAGDIR; ;;
  staging-development)    DIR="down"; FROMSITE=$STAGSITE; FROMDIR=$STAGDIR; TOSITE=$DEVSITE;  TODIR=$DEVDIR; ;;
  *) echo "usage: $0 development production | development staging | production development | production staging | staging development" && exit 1 ;;
esac

read -r -p "Would you really like to reset the $TO database and sync $DIR from $FROM? [y/N] " response

if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
  cd ../ &&
  wp "@$TO" db export &&
  wp "@$FROM" db export - | wp "@$TO" db import - &&
  wp "@$TO" search-replace "$FROMSITE" "$TOSITE" &&
  rsync -az --progress "$FROMDIR" "$TODIR"
fi

Edit: though I’m still using WP Migrate DB, I figured I’d add in the option to skip syncing uploads, so after the case block I changed to the following:

read -r -p "Would you like to sync the uploads folder as well? [y/N] " uploads
read -r -p "Would you really like to reset the $TO database and sync $DIR from $FROM? [y/N] " response

if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
  cd ../ &&
  wp "@$TO" db export &&
  wp "@$FROM" db export - | wp "@$TO" db import - &&
  if [[ "$uploads" =~ ^([yY][eE][sS]|[yY])$ ]]; then
    wp "@$TO" search-replace "$FROMSITE" "$TOSITE" &&
    rsync -az --progress "$FROMDIR" "$TODIR"
  else
    wp "@$TO" search-replace "$FROMSITE" "$TOSITE"
  fi
fi
1 Like

Wouldn’t this be a great candidate for a GitHub repository?

1 Like

–skip-columns=guid should be used when replacing, see
https://codex.wordpress.org/Changing_The_Site_URL#Important_GUID_Note

I am working on a repo here. Raquelle as author (@cedarstay ) as well as @ben have been mentioned for the script they made and I added there. Thanks so much for sharing this and teaching me more about aliases and shell scripts! README is not quite done yet and tweaks me be needed. Feel free to submit pull requests or clone it.

2 Likes

Also a plain backup option would be nice that dumps the database and uploads/ folder to a specific local path (for remote regular backups).

Actually another pull request by @guilro is in line for automating database and file backups using Stouts.backup Ansible role with Duplicity and is mentioned here: https://github.com/roots/trellis/pull/650 . I think that would be really good to have and can be configured in many different ways.

2 Likes

I use the --export option of wp search-replace for this and also add gzip. No wp-aliases though, but not much different. It’s basically like:

ssh $srv1 "cd $dir1; wp search-replace 'http://$srv1' 'http://$srv2'  --export | gzip" \
| ssh $srv2 "cd $dir2; gunzip | wp db import -"
1 Like

Just did a run to move stuff from a dev site to a production site. Latter is a demo so worries there. But I ran into an error

./sync-all.sh development production
Would you really like to reset the production database and sync up from development? [y/N] y
mysqldump: Can't create/write to file 'filathlos_imagewize_com_production-a822007.sql' (Errcode: 13 "Permission denied")

Must be a permissions issue. But should did not work using user web?

Well when I used the user web in the wp-cli.yml file it all worked

./sync-all.sh development production
Would you really like to reset the production database and sync up from development? [y/N] y
Success: Exported to 'filathlos_imagewize_com_production-a9ab231.sql'.
Success: Imported from '-'.

I only had a Sage error:

Error: Sage › ErrorAutoloader not found.. You must run composer install from the Sage directory.

, but when I commented out build-before.yml and ran deployment again I solved that too

Thank you for this very helpful script!

In my case, I ran sync.sh from within my Trellis-provisioned development vagrant vm and it only worked when I changed the first line from #!/bin/sh to #!/bin/bash. Otherwise it will throw the following error on line 25 of the script:

./sync.sh: 25: ./sync.sh: Syntax error: "(" unexpected (expecting "then")

I’m far from being a Unix shell expert though, so I’m wondering if anyone has encountered this?

2 Likes