A DDEV provider add-on that syncs a Pressable
WordPress site's database and uploads to and from your local DDEV project with
ddev pull pressable and ddev push pressable.
It runs entirely over the SSH and WP-CLI access your Pressable site already has.
There is no Pressable API token, no plugin, and nothing to enable on the
platform. Under the hood it uses SSH, WP-CLI (wp db export / wp db import /
wp search-replace), and rsync.
| Direction | What moves | Command |
|---|---|---|
| Pull | Remote DB + uploads down to local | ddev pull pressable |
| Push | Local DB + uploads up to a staging site | ddev push pressable |
Site URLs are rewritten automatically in both directions with wp search-replace
(serialized-data safe), so the local site renders at its *.ddev.site URL and a
pushed site renders at its own URL. Your theme and plugin code is not synced.
That comes from your own git repository, the way DDEV intends.
- DDEV
v1.24.0or newer. - A Pressable site, and the SSH key for it loaded locally.
- A WordPress DDEV project on your machine (
ddev config --project-type=wordpress).
ddev add-on get pressable/ddev-pressableThen configure the project (below) and ddev restart. Commit the resulting
.ddev directory to version control so your team shares the same setup.
SSH/SFTP usernames on Pressable are per-site, not per-account, so one DDEV project maps to one Pressable site with one username. Set it on the project rather than committing it to the provider file:
ddev config --web-environment-add="PRESSABLE_SSH_USER=<site-ssh-user>"
ddev restartThree ways to find the username:
- Control panel. Open the site, then its SFTP/SSH section.
- API.
GET /v1/sites/{id}/ftpreturnsusernameandsftp_domain(Doorkeeper OAuth, scopesftp_read/sites_read). - MCP.
list_site_ftp_accountsreturns the username;get_ftp_account_detailsreturns the username andsftp_domain.
The SSH host defaults to ssh.pressable.com. Override it only if needed with
PRESSABLE_SSH_HOST.
DDEV runs the sync inside its web container, which cannot reach the macOS
Keychain, so load your key into DDEV's ssh-agent once per ddev session:
ddev auth sshThis is standard for every SSH-based DDEV provider.
Direction and granularity are built into DDEV's pull/push flags:
| Want | Command |
|---|---|
| DB + files | ddev pull pressable |
| DB only | ddev pull pressable --skip-files |
| Files only | ddev pull pressable --skip-db |
| Download, do not import | ddev pull pressable --skip-import |
The same --skip-db / --skip-files flags work on ddev push pressable, so
ddev push pressable --skip-files pushes just the database to a staging site.
- Pull production to local for development.
ddev pull pressablebrings the database and uploads down; your code comes from git. - Push local to staging for a client demo.
ddev push pressableto a staging site, both database and files, or--skip-filesfor the database alone. - Database-only refresh.
ddev pull pressable --skip-filesgrabs the latest content without re-downloading a large media library. - Files-only sync.
ddev pull pressable --skip-dbpulls new media without clobbering your local database state. - Selective-table pull. Exclude bulky log/transient tables from a refresh,
or (advanced) import only a chosen set (see below).
ddev pullreplaces the local database, so use--skip-dbif you want to leave it untouched. - Two-environment flow. Pull content from production (read-only), develop locally, push to staging for review, and ship code through git, so the database and files never touch the live site.
ddev pull replaces the local database (it drops the existing tables before
importing), so these variables control what gets imported, not what is kept.
To leave your local database untouched, use --skip-db instead.
The common, safe use is to exclude bulky log or transient tables while keeping everything else:
# Import everything except these (e.g. skip bulky log/transient tables)
ddev config --web-environment-add="PRESSABLE_DB_EXCLUDE_TABLES=wp_actionscheduler_logs,wp_actionscheduler_actions"PRESSABLE_DB_TABLES imports only the listed tables and drops the rest,
which is advanced: a WordPress site needs its core tables to boot, and the
post-pull URL rewrite only runs when wp_options is among the imported tables.
Include the full set you need:
ddev config --web-environment-add="PRESSABLE_DB_TABLES=wp_options,wp_posts,wp_postmeta,wp_users,wp_usermeta"PRESSABLE_DB_TABLES takes precedence over the exclude list. Filtering is
whole-table; row- and field-level filtering is out of scope.
Local tool versions live in your own .ddev/config.yaml, not in this add-on, so
there is nothing to maintain here per release. To match local to the site:
- PHP. Mirror the site's control-panel value with
php_version. - Database. Any recent MariaDB imports a
wp db exportdump fine. Pinmariadb_version: "10.11"only if you want exact parity. - Webserver.
webserver_type: nginx-fpm. - WordPress core. This is your own codebase, not a config value. Pull moves the database and uploads only, never core.
- Push to staging, never to a live site. A database push overwrites the
remote database. On a live site that destroys everything created since the
dump (orders, comments, form entries).
ddev pushalways prompts for confirmation; do not bypass it with-y. Keep pushes pointed at staging sites. - Files push is additive by default. It never deletes remote media. Mirror
mode (deleting remote files missing locally) is opt-in only; edit the
files_push_commandrsync line in.ddev/providers/pressable.yamlto add--delete, and understand the risk first. - Object cache after a push. A
ddev pushimports the database with a rawwp db import, which bypasses the hosting platform's object cache, so reads can be stale until the cache is flushed. The provider runswp cache flushon the remote automatically after every push. If you need the rendered HTML fresh immediately (not just the data layer), also run a full-page or edge-cache purge, for examplewp edge-cacheagainst the remote.
- Transport.
ssh <PRESSABLE_SSH_USER>@ssh.pressable.com, wherewpis on the PATH and auto-locates the install from the login home directory. - Pull.
wp db export -streams a dump over SSH into.ddev/.downloads/db.sql.gz;rsyncbringshtdocs/wp-content/uploads/into.ddev/.downloads/files/. DDEV imports both, then apost-import-dbhook rewrites the production URL to your local DDEV URL. - Push. DDEV exports the local database; the provider captures the remote URL,
imports the local dump over SSH, rewrites URLs back to the remote URL with
wp search-replace, runswp cache flush, andrsyncs uploads up.
This add-on is versioned by git tags: ddev add-on get pressable/ddev-pressable
installs the latest GitHub release.
Automatic (default). Every merge to main cuts a release once the tests
workflow passes —
.github/workflows/release-on-merge.yml
computes the next version, tags it, and publishes the release.
- Bump level defaults to a patch (
1.2.3 -> 1.2.4). For a larger bump, add arelease:minororrelease:majorlabel to the PR, or put#minor/#majorin the merge commit message. - Skip a release for a given merge with a
release:skiplabel or[skip release]in the commit message.
Manual (out-of-band). To cut a release without a merge, run the Ruby helper
locally; pushing the tag triggers
.github/workflows/release.yml:
.github/scripts/release.rb # patch bump (default), e.g. 1.2.3 -> 1.2.4
.github/scripts/release.rb minor # 1.2.3 -> 1.3.0
.github/scripts/release.rb major # 1.2.3 -> 2.0.0
.github/scripts/release.rb 1.5.0 # explicit version
.github/scripts/release.rb --dry-run minorIt validates that the tree is clean and on main, computes the next version from
the latest tag, then creates and pushes the annotated tag.
Maintained by Pressable. Scaffolded from
ddev/ddev-addon-template.
Licensed under Apache 2.0.