Install
Upload it under Plugins → Add New Plugin → Upload Plugin, then activate.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/g000m/updraftplus-multi-destination/releases/download/v1.3.0/updraftplus-multi-destination.zipA WordPress plugin that extends UpdraftPlus (free) so every backup uploads to multiple remote destinations simultaneously, reusing UpdraftPlus's own upload engine. No UpdraftPlus files are patched, so UpdraftPlus updates normally.
Verified against UpdraftPlus 1.26.5.
Releasing a new version
- Bump
Version:in the plugin header andStable taginreadme.txt. - Commit and push.
- Publish a GitHub release for the new tag (web UI or
gh release create) - this is the actual trigger; a git tag on its own does nothing. .github/workflows/release.ymlrunscomposer install --no-devand attaches the built zip to the release automatically (~1-2 min).- Confirm the asset attached. PUC requires it (
REQUIRE_RELEASE_ASSETS) and won't offer a release that doesn't have one. - Installed sites pick up the update within 12 hours, or immediately via Dashboard -> Updates -> "Check again".
How it works
Multi-destination unlock
UpdraftPlus core already uploads to every service in the updraft_service array;
the single-destination limit is enforced at three filterable gate points:
| Gate | Native behaviour (free) | This plugin |
|---|---|---|
updraftplus_savestorage |
reduces the array to its last element | returns the full array (UDMD_Multi_Storage::preserve_all_services()) |
updraftplus_storage_printoptions_multi |
checkboxes get no multi class, so selecting one unchecks the rest |
returns 'multi', making checkboxes independent |
updraftplus_storage_printoptions |
prints a "get Premium" notice | suppresses it |
These filters cover both the save path and every read path (job setup, pruning, the settings form, "Backup Now"), so multi-selection flows through scheduled backups, manual backups, uploads and retention pruning using entirely native code. Each callback defers if another handler (e.g. Premium's multi-storage add-on) already acted, so coexistence is safe.
Cloudflare R2, on the native S3-Compatible method
R2 runs on UpdraftPlus's own S3-Compatible (Generic) (s3generic) method, which
already handles R2's transport requirements (SigV4 signing, virtual-host bucket
addressing). Upload, retries, download, deletion, pruning and restore are all native
code paths. UDMD_R2_Helper only relabels the method in the storage picker and
injects an R2 quick-start note into the native config panel.
Self-updates
UDMD_Updater::init() (in includes/class-udmd-updater.php) wires up
yahnis-elsts/plugin-update-checker
(PUC v5) to poll GitHub releases, feeding WordPress's normal update UI/upgrader
(including per-plugin auto-updates). It runs outside the UpdraftPlus-presence guard,
so the plugin can update itself even while UpdraftPlus is deactivated.
- Repository:
UDMD_Updater::REPO_URL, overridable via theudmd_update_repository_urlfilter. - Release assets required:
vendor/isn't committed, so GitHub's auto-generated source archive can't self-update. See Releasing a new version above. - Private repo: define
UDMD_GITHUB_TOKENinwp-config.php(a fine-grained PAT with read access to the repository). - Local development:
vendor/is gitignored - runcomposer installafter cloning. Without it, self-updates are disabled but core functionality is unaffected.
Files
updraftplus-multi-destination/
├── updraftplus-multi-destination.php # bootstrap (incl. update-checker init)
├── uninstall.php # removes legacy/deprecated option names
├── composer.json / composer.lock # yahnis-elsts/plugin-update-checker ^5.6
├── readme.txt # WordPress.org-style readme
├── vendor/ # gitignored; composer install locally,
│ # bundled into release zips by CI
├── .github/workflows/release.yml # builds & attaches the release zip asset
└── includes/
├── class-udmd-multi-storage.php # the three unlock filters
├── class-udmd-r2-helper.php # R2 labelling + config-panel help
└── class-udmd-updater.php # GitHub-releases self-updater (PUC)
Usage
- Activate UpdraftPlus (free), then this plugin.
- Settings -> UpdraftPlus Backups -> Settings: tick every destination you want - the icons now multi-select instead of toggling each other off.
- Configure R2 in the S3-Compatible panel:
- access key / secret key from an R2 API token (Object Read & Write);
- location:
bucketorbucket/path; - endpoint:
<account-id>.r2.cloudflarestorage.com(jurisdiction buckets:<account-id>.eu.r2.cloudflarestorage.com); - signature version: SigV4. Use the Test button, then Save Changes.
- Every scheduled or manual backup now uploads to all selected destinations, and retention rules prune old sets on each of them.
Development notes / verification
php -lclean on all files (PHP 8.4).- A smoke harness runs the plugin against real UpdraftPlus 1.26.5 sources: the
multi-storage filter interaction, template injection through
s3generic, and the method-id gates noted under Known Limitations.
Known limitations
- R2 rides on the native
s3genericmethod id rather than a dedicated one, because UpdraftPlus (free) hard-requires storage method IDs to both live inside its ownmethods/directory and appear in a non-filterable internal list (get_settings_keys()) - a third-party method id can't survive the upload path without patching core files. A dedicatedcloudflarer2id was tried first and failed on the first real upload for exactly this reason. - One instance per method via the UI (multiple simultaneous R2 buckets is Premium's multi-instance territory).
- R2 shares the single
s3genericslot with any other S3-compatible provider you may want to use at the same time.
Releases
1 release. Each count is every asset in that release; expand a row for the breakdown.