Deploying a WordPress theme manually can be a pain, especially when dealing with SSH, rsync, GitHub, and database migrations. After some trial and error, I figured out a clean and efficient way to deploy my Swagdrip WordPress theme from my local development environment to my live server.

This post documents everything that worked (and didn’t work), so you don’t have to suffer through the same debugging process.

The Goal

  • Push theme updates without breaking the live site
  • Exclude unnecessary files (node_modules, .git, .DS_Store, .map, etc.)
  • Automate deployment with GitHub + SSH + Rsync
  • Ensure database URLs are updated after sync
  • Verify everything works after deployment

Step 1: Prepare the Local Environment

I’m using Local by Flywheel for local development. My theme lives in:

/home/mnrdjmke/public_html/wp-content/themes/swagdrip/

I also track my theme with Git on GitHub at:

git@github.com:eboy79/swagdrip.git

Before deploying, I ensure everything is committed:

git add .
git commit -m "Updated theme for deployment"
git push origin main

Step 2: Deploying the Database to Live Server

First, I export my local database:

wp db export local-db.sql

Then, I securely copy it to my live server:

scp -P 21098 local-db.sql mnrdjmke@198.54.125.196:/home/mnrdjmke/public_html/

On the live server, I import it:

wp db import /home/mnrdjmke/public_html/local-db.sql

Then, update the URLs to ensure everything points to the live domain:

wp search-replace 'https://mnrdsgn.local' 'https://mnrdsgn.com' --skip-columns=guid
wp cache flush

Step 3: Deploying the Theme Files with Rsyn

Since I only want to transfer the theme files (excluding unnecessary dependencies), I use rsync:

rsync -avz --progress -e "ssh -p 21098" \
  --exclude "node_modules" \
  --exclude ".git" \
  --exclude "package-lock.json" \
  --exclude ".DS_Store" \
  --exclude "*.map" \
  --exclude "*.d.ts" \
  --exclude "package.json" \
  --exclude "rollup.config.js" \
  "/home/mnrdjmke/public_html/wp-content/themes/swagdrip/" \
  mnrdjmke@198.54.125.196:/home/mnrdjmke/public_html/wp-content/themes/swagdrip/

This ensures only relevant theme files are uploaded, keeping the live server clean.

To verify everything transferred:

ssh -p 21098 mnrdjmke@198.54.125.196
ls -lah /home/mnrdjmke/public_html/wp-content/themes/swagdrip/

Step 4: Clearing Cache & Verifying Deployment

After the files are synced, I clear any cached data:

wp cache flush

Then, I check my live site at https://mnrdsgn.com to confirm changes.

If styles or scripts don’t update, I run:

rm -rf wp-content/cache/*

And hard refresh (Cmd + Shift + R on Mac, Ctrl + Shift + R on Windows).

Step 5: Automating with GitHub

Since I want to push from GitHub to the live site, I set up a post-receive Git hook.

On the Live Server:

cd /home/mnrdjmke/public_html/wp-content/themes/swagdrip
git init
git remote add origin https://github.com/eboy79/swagdrip.git
git pull origin main

Now, every time I push to GitHub, I just SSH in and pull:

ssh -p 21098 mnrdjmke@198.54.125.196
cd /home/mnrdjmke/public_html/wp-content/themes/swagdrip
git pull origin main

For full automation, I’ll set up a GitHub Actions workflow (coming soon).

What Worked & What Didn’t

What worked:

  • scp for database migration ✅
  • rsync for fast, efficient theme deployment ✅
  • wp search-replace for URL updates ✅
  • wp cache flush to ensure instant updates ✅
  • Git tracking on GitHub for version control ✅

What didn’t work (and got fixed):

  • Using scp for themes – too slow & error-prone ❌ → Fixed with rsync
  • Accidentally tracking node_modules in Git ❌ → Fixed by adding to .gitignore
  • Not excluding .map files ❌ → Fixed by updating rsync excludes
  • Forgetting to clear cache after deployment ❌ → Fixed with wp cache flush

Final Thoughts

This setup allows me to push WordPress theme updates fast and efficiently without breaking the live site. If you’re struggling with manual deployments, this workflow will save you time and headaches.

🚀 Next Step: Automating this with GitHub Actions to make it one-click deploy. Stay tuned!

Got Questions?

Hit me up on GitHub: @eboy79 or comment below!