Staging Deployment Script
This CLI deploys your local WordPress site or theme to a remote staging server over SSH using rsync, with optional database push via WP-CLI. It’s configurable, safe by default (dry runs, excludes), and interactive when needed.
What It Does
- Files: Deploys either the entire WordPress site or one theme directory
- DB: Optionally exports local DB, uploads to remote, imports, and does URL search-replace
- Config: Reads defaults from
deploy.config.json, allows CLI overrides - Safety: Dry-run, verbose logs, optional
--deleteto mirror exact state - Smart: Auto-detects your theme name (if only one non-twenty* theme exists)
- Interactive: Guided setup when staging not configured (e.g., BBCDEV or custom SSH target)
- Build step: Asks if you want to run
npm run buildin your theme before pushing
Requirements
- Local & Remote:
ssh,rsync - WP-CLI: Needed for DB pushes (both local and remote)
- Auth: SSH key-based access to the remote server
Preconfigured NPM scripts (package.json)
{
"scripts": {
"deploy": "node ./scripts/deploy.js",
"deploy:theme": "node ./scripts/deploy.js --theme-only",
"deploy:full": "node ./scripts/deploy.js --full --push-db --include-uploads",
"deploy:db-only": "node ./scripts/deploy.js --db-only"
}
}
What Each Script Does
npm run deploy
Full site files only (no DB).- Mode: Full (because no
--theme-only) - Uploads: excluded (default)
- DB: not pushed
- Use when: you want to sync code/config/theme/plugin changes without touching media or DB.
- Mode: Full (because no
npm run deploy:theme
Push only the active theme folder.- Mode: Theme-only (
--theme-only) - Targets:
wp-content/themes/<theme>/ - Use when: you changed only theme code (safe, fast, minimal).
- Mode: Theme-only (
npm run deploy:full
Push entire site + database, and include uploads.- Mode: Full (
--full) - Uploads: included (
--include-uploads) - DB: pushed (
--push-db) with optional search-replace (iflocalUrl/stagingUrlset) - Use when: you’re syncing a full snapshot (code + media + DB) to staging.
- Mode: Full (
npm run deploy:db-only
Only push the database.- Mode: DB-only (
--db-only) - Files: untouched
- Use when: content or settings changed locally and you want them on staging, but files are already up to date.
- Mode: DB-only (
Configuration
Defaults (can be overridden by
deploy.config.jsonor flags):localPath: local WP root (www)remotePath: server WP root (/var/www/html)host,user,port: SSH targetthemeName:null(auto-detect if possible)delete:false(rsync--deletedisabled by default)excludeUploads:true(skip uploads/cache on full deploys)wpCli:wplocalUrl,stagingUrl: used for DB search-replacewpEnvLocal:local,wpEnvRemote:staging
Interactive target setup (when
stagingUrlmissing):- Choose BBCDEV or Custom
- Automatically fills
remotePath/stagingUrlfor BBCDEV subsites - Writes your choices back to
deploy.config.json
Modes
- Full site:
--full(default if--theme-onlynot passed) - Theme only:
--theme-only(syncs onlywp-content/themes/<theme>) - DB only:
--db-only(no file sync; just push DB) - DB push after files: add
--push-dbto full/theme
Safety & Logging
--dry-run: print commands and rsync plan without changing anything--verbose/-v: more detailed output- Preflight checks: verifies
ssh,rsync(andwpif needed), confirms paths exist - SSH probe: quick connection test before running
File Deployment (rsync)
Full Site (--full)
- Flags: archive+compress, partial, progress, protect-args
- Excludes (by default):
.git,node_modules, logs, temporary folders, themevendor/,src/, tooling files, etc. - Uploads: skipped unless you pass
--include-uploads - Delete: opt-in with
--deleteto mirror exact state - Remote path: ensures directory exists before rsync
Theme Only (--theme-only)
- Syncs only
wp-content/themes/<theme>/ - Ensures remote theme directory exists before rsync
Database Push (Local → Staging)
Triggered by --push-db (after files) or --db-only.
Flow:
- Export local DB to
www/_db/local-YYYYMMDD-HHMMSS.sql(addsDROP TABLE) - Rsync dump → remote
_db/directory (creates it if needed) - Remote import via
wp db import - URL search-replace (skips GUIDs) if both
localUrlandstagingUrlare set- Disable with
--no-search-replace
- Disable with
- Cleanup: removes remote dump after import
Env vars: sets WP_ENV=local for local WP-CLI, WP_ENV=staging for remote (configurable)
Default File Excludes
The deploy script skips certain files and folders by default to:
- Avoid sending unnecessary or local-only files
- Prevent overwriting sensitive server files (like media or configs)
Always Excluded
- macOS/OS junk:
.DS_Store - Version control:
.git/ - Local dependencies:
node_modules/ - Temp folders:
_temp/ - Logs:
*.log - Local build/config files:
package.json,package-lock.json,composer.json,composer.lock - Theme vendor dirs:
wp-content/themes/*/vendor/ - Local tooling files:
vite.config.js,.phpcs.xml.dist,.postcssrc - Source folders:
/src/(unbuilt assets)
Uploads & Cache
If excludeUploads is true (default), also skips:
wp-content/uploads/(media library)wp-content/cache/wp-content/upgrade/
This prevents large media syncs or accidental overwrites of staging uploads.
Tip
- To include uploads on a full deploy, use the
--include-uploadsflag
(e.g.,npm run deploy:fullalready does this). - You can modify this exclude list in the script to match your project’s needs.
Prompts & Convenience
- Build theme? Optional
npm run buildinside your theme prior to deploy - Deploy summary: Prints a clear run-down (mode, paths, delete/exclude flags, DB options) and asks to confirm before executing
Useful CLI Flags
- Scope:
--full,--theme-only,--db-only,--push-db - Safety:
--dry-run,--verbose,--delete,--no-search-replace - Paths/Target:
--host,--user,--port,--path(remote),--local(local root) - Theme:
--theme <name> - DB/URLs:
--wp-cli <cmd>,--local-url <url>,--staging-url <url>
(Any of these override config file values for the current run.)
Examples
Full deploy (files only):
./deploy.js --fullTheme only:
./deploy.js --theme-onlyFull deploy + DB:
./deploy.js --full --push-dbDB only:
./deploy.js --db-onlyDry run + verbose:
./deploy.js --full --dry-run --verboseCustom target just for this run:
./deploy.js --full --host ssh.example.com --user deploy --path /var/www/html --port 2222
Tips
- Keep
uploadsexcluded on full pushes unless you really intend to overwrite remote media - Use
--deleteonly when you want the remote to exactly match local (dangerous on shared targets) - Set
localUrl/stagingUrlindeploy.config.jsonto automate post-import URL rewrites - For repeated targets, let the interactive setup write persistent values to
deploy.config.json