0+
September 30, 2026
September 7, 2026
Your media library is probably the biggest thing on your server. OmniOffloader moves it to cloud object storage, serves it from your own domain or CDN, and frees the disk space it was using — without changing a single URL in your content.
Every upload is copied to the cloud automatically: the original, every generated thumbnail, the -scaled version and modern WebP/AVIF sources. Image URLs and srcset attributes are rewritten as pages render, so your posts, pages and page builders keep working exactly as before, and nothing in your database is search-replaced.
And because offloading should never be a one-way door, Bring Back downloads everything from the cloud to your server again — one file or the whole library — and hands your URLs back to local paths.
Documentation: step-by-step provider guides, every feature, WP-CLI and developer hooks at omnioffloader.vercel.app.
OmniOffloader is designed to run on a small shared hosting plan just as well as on a VPS.
Filters: omnioffloader_cloud_providers, omnioffloader_object_acl, omnioffloader_attachment_key, omnioffloader_attachment_delete_keys, omnioffloader_should_offload_attachment, omnioffloader_use_async_upload, omnioffloader_should_apply_retention, omnioffloader_media_block_names, omnioffloader_log_provider_errors, omnioffloader_multipart_threshold, omnioffloader_transfer_concurrency, omnioffloader_bulk_failure_limit.
Actions: omnioffloader_before_offload, omnioffloader_after_offload, omnioffloader_before_restore, omnioffloader_after_restore.
REST API namespace: omnioffloader/v1. WP-CLI: wp omnioffloader. Full reference with examples: Hooks and WP-CLI.
This plugin bundles the AWS SDK for PHP (Apache-2.0), which is GPL-compatible under GPLv3 — covered by this plugin’s “GPL-2.0-or-later” license.
This plugin connects to the cloud storage provider you choose and configure in its settings. Nothing is sent anywhere until you enter credentials for a provider, and it only ever connects to that provider.
What is sent and when: your media files (originals, thumbnails and other generated sizes) and their file paths are uploaded when media is offloaded — automatically on upload, from Bulk Offload, the Media Library, or WP-CLI. Files are downloaded again when you use Bring Back or apply a looser retention policy, and deleted from the bucket when you delete an attachment with Mirror Delete on, or restore with “delete from cloud” on. Test Connection sends a request to check that your bucket is reachable. Every request is signed with the access key you entered; the secret key itself is never transmitted. Visitors then load the offloaded files from the storage or CDN address you configured.
No analytics, tracking or other data is sent to the plugin author or any other party.
Depending on the provider you select:
omnioffloader folder to /wp-content/plugins/.Amazon S3, Cloudflare R2, DigitalOcean Spaces, Backblaze B2 and Wasabi each have a dedicated setup. Anything else that speaks the S3 API — MinIO, Storj, OVHcloud, Linode Object Storage, Scaleway and so on — works through Any S3-Compatible Storage, where you supply the endpoint and region yourself.
https://media.yourdomain.com) or enable the public r2.dev URL, so your files can be served publicly.https://<account-id>.r2.cloudflarestorage.com) from the bucket settings.Full guide: omnioffloader.vercel.app/providers/cloudflare-r2/
s3:GetObject on the bucket with a bucket policy, or put an Amazon CloudFront distribution in front of it.us-east-1) and your CloudFront or CDN URL (or leave it blank to serve directly from S3).Full guide: omnioffloader.vercel.app/providers/amazon-s3/
https://nyc3.digitaloceanspaces.com) and region (nyc3).Full guide: omnioffloader.vercel.app/providers/digitalocean-spaces/
https://s3.us-east-005.backblazeb2.com) and its region (us-east-005).keyID and applicationKey.Full guide: omnioffloader.vercel.app/providers/backblaze-b2/
us-east-1).Full guide: omnioffloader.vercel.app/providers/wasabi/
https://link.storjshare.io/s/<KEY>/<BUCKET>. Replace /s/ with /raw/.https://gateway.storjshare.io, Region to us-east-1, turn on Use Path-Style Endpoint, enter your keys and Bucket Name, and paste the https://link.storjshare.io/raw/... URL as the Custom Domain / CDN URL.The same fields work for MinIO, OVHcloud, Linode, Scaleway and other S3-compatible services. The optional Provider Label lets you name the provider as it appears in the plugin. Full guide: omnioffloader.vercel.app/providers/s3-compatible/
It matters most when you offload media that is already in your library but not in the cloud yet — with Bulk Offload, Media Library bulk actions or WP-CLI — and when you use Bring Back. New uploads are offloaded in the background as they arrive, so you rarely notice their speed. The setting chooses how many files are uploaded or downloaded at the same time:
All four run in the same single PHP process; a faster setting overlaps the time spent waiting on the network instead of starting more processes. Each extra file only adds a little memory and bandwidth. Bulk Offload, Bring Back, new uploads and WP-CLI all follow this setting.
It depends mostly on how quickly your server reaches your storage provider, how large your files are, and how many thumbnail sizes your theme creates. A higher Transfer Speed finishes sooner on a server that can handle it.
Jobs run in the background and keep going after you close the tab. On hosts that block WordPress’s internal loopback requests, the admin screen drives the job instead — there, leave the Offload page open until it finishes, or use WP-CLI.
No. URLs are rewritten as pages render, so posts, pages, featured images and responsive srcset attributes all keep working. Nothing in your post content is edited, and no database search-replace is needed.
Yes — that is what Bring Back is for. It downloads your media from the cloud to its original paths, checks that every file arrived, and then stops rewriting URLs so everything serves locally again. You can restore a single attachment, a set number, or the whole library. The cloud copy is kept unless you turn on deleting it after restore.
That depends on the retention policy you used. With Retain Local Files, every file is still on your server and nothing changes. With Smart Local Cleanup or Full Cloud Migration, some or all local files were deleted after upload, so URLs would point at files that are no longer on disk. Run Bring Back before deactivating if you used either cleanup policy.
No. A copy carries the live site’s settings and access keys, so without protection it would upload into the live bucket (a new file with the same name could overwrite one the live site added later) and, with Mirror Delete on, delete files the live site still uses. OmniOffloader recognises a copy automatically and switches to Safe mode:
WP_ENVIRONMENT_TYPE, set by many managed hosts and local tools), orlocalhost, *.local or *.test.In Safe mode nothing is uploaded to or deleted from your cloud storage. Media already in the cloud keeps loading from it, and new uploads stay on the copy’s own server. Bring Back is turned off too; to download media from the cloud to the copy, turn on Allow Bring Back on a copy (download only) in Settings — the cloud copy is then always kept. A banner explains why Safe mode is on. If your live site really moved to a new domain, click This is the live site. To decide yourself, add define( 'OMNIOFFLOADER_SAFE_MODE', true ); (or false) to wp-config.php, or turn off Protect the live site when this is a copy in Settings.
Yes, for example example.com, shop.example.com and blog.example.com. Install OmniOffloader on each site, enter the same bucket, keys and custom domain, and give each site its own folder under Settings Custom Path Prefix (for example www, shop and blog). Each site’s files then live under their own folder, such as https://cdn.example.com/shop/2026/09/photo.jpg.
Separate sites share no database, so without a folder of their own two sites would store files under the same names. One site’s upload would then overwrite the other’s file, and Mirror Delete on one site would delete files the other still uses. To prevent this, each site marks its folder with a small .omnioffloader-site.json file naming the site. Settings refuses a folder another site already uses. If a site finds another site’s marker in its folder, it switches to Safe mode and a banner explains why. Nothing is uploaded or deleted until you choose a different Path Prefix. If the folder really belongs to this site (for example after a domain change), click This folder belongs to this site.
For a hard guarantee on Amazon S3, give each site its own access key, limited to its own folder.
No. The default policy, Retain Local Files, deletes nothing — the cloud simply becomes a second copy. Choose Smart Local Cleanup to delete only generated thumbnails while keeping every original, or Full Cloud Migration to reclaim the most space. Local files are only removed after the upload has been confirmed in your bucket.
A retention policy is applied when a file is offloaded, so a new policy only affects new uploads at first. Go to OmniOffloader Tools Apply Retention Policy to Existing Media (or run wp omnioffloader retention) to update media you offloaded earlier. Before a local file is deleted, its cloud copy is checked by size. Files missing from the cloud are uploaded first. A file whose cloud copy differs is uploaded again and checked; if that fails, the local file is kept and reported. Moving to a looser policy (for example from Full Cloud Migration back to Retain Local Files) downloads the local copies again.
Most storage buckets do not serve files publicly by default, and Cloudflare R2 has no public URL at all until you connect one. Pointing a custom domain or CDN hostname at your bucket is what makes your media reachable — and it lets the files be cached at the edge.
Yes. Define them as constants in wp-config.php, named OMNIOFFLOADER_{PROVIDER}_{FIELD} — for example:
define( 'OMNIOFFLOADER_CLOUDFLARE_R2_KEY', '...' );
define( 'OMNIOFFLOADER_CLOUDFLARE_R2_SECRET', '...' );
Constants take priority over saved values, and the settings screen shows those fields as locked. Secrets are never sent back to the browser either way, and stored credentials are kept out of WordPress’s autoloaded options.
Yes. OmniOffloader Tools lists every command and option with copy buttons.
wp omnioffloader offload --all [--limit=<number>] [--dry-run]
wp omnioffloader offload --ids=12,34
wp omnioffloader restore --all [--limit=<number>] [--delete-cloud] [--dry-run]
wp omnioffloader retention [--policy=<0|1|2>] [--dry-run] [--format=json]
wp omnioffloader status
Every write command supports --dry-run, and destructive options ask for confirmation unless you pass --yes. Commands refuse to start while another bulk job is running (--force overrides this), so two jobs never touch the same files. WP-CLI offloads use your Transfer Speed setting.
Only administrators (users with the manage_options capability). Other users keep their normal WordPress rights: they upload and delete their own media, and with Mirror Delete on, deleting an attachment also removes its cloud copy.
Files above 64 MB are uploaded in parts, so a dropped connection costs one chunk rather than the whole transfer, and files larger than 5 GB are supported. If a transfer is still cut short by your host’s time limit, that attachment is reported with an explanation and the job moves on.
Yes. The plugin’s own REST requests tell page caches not to store them (including LiteSpeed Cache and Breeze), and bulk progress stays live under Redis or Memcached object caching. On the front end the plugin only rewrites URLs and does not add database queries per image.
Serve Media from Cloud
WP-CLI: background runs and a stop command
wp omnioffloader offload, restore and retention take --background: the job keeps running after you close the terminal, with its output in a log file.wp omnioffloader stop ends the running job from any terminal. A WP-CLI run finishes the file it is transferring first; a job started from the admin screen is cancelled.wp omnioffloader status shows a running WP-CLI job: progress, failures, process and log file.Fixes
wp omnioffloader offload, restore or retention now releases the job lock right away, as Ctrl+C does. Before, the next run was refused for up to 10 minutes.Documentation
Apply Retention Policy to Existing Media
wp omnioffloader retention [--policy=<0|1|2>] [--ids=<ids>] [--limit=<number>] [--dry-run] [--yes] [--force]. wp omnioffloader status now reports media that follows an older policy.omnioffloader_should_apply_retention to keep specific attachments’ local files.Faster Offloading
wp omnioffloader offload. An attachment’s files (original and every generated size) now upload side by side instead of one after another, and at any speed above Low a few attachments share one batch, with their main files confirmed in the bucket together. Everything still runs inside one PHP process, and each attachment is only marked offloaded once every one of its files uploaded and its main file is confirmed in the bucket.omnioffloader_transfer_concurrency filter.max_execution_time), so WordPress reloads less often during a bulk job.Security
.. before creating any directory. File paths from attachment metadata that point outside the uploads folder are ignored for upload, cleanup and restore.Performance
wp omnioffloader retention --dry-run and the offload/restore dry runs load attachments 200 at a time instead of one by one.Fixes
--limit must be a positive number (a typo no longer means “the whole library”), --ids and --all can’t be combined, and skipped IDs are reported. restore stops after 10 failures in a row, status exits with an error code when the bucket is unreachable, and retention --dry-run supports --format=json|csv.vendor folder shows an admin notice instead of a fatal error.wp omnioffloader offload and restore.omnioffloader_should_offload_attachment filter now show as “Skipped” in the activity log and WP-CLI summary instead of as failures, and no longer keep a “Queued” badge.omnioffloader_transfer_heartbeat fires every 30 seconds during uploads and downloads.omnioffloader_free_disk_space lets a host or developer supply the real space left in the quota.WP_ENVIRONMENT_TYPE and local addresses; a banner explains why, with a “This is the live site” button for a real domain move. Control it with the new Settings option “Protect the live site when this is a copy” or the OMNIOFFLOADER_SAFE_MODE constant. wp omnioffloader status shows the mode; wp omnioffloader offload and restore refuse to run in Safe mode (restore works when Bring Back is allowed, but never with --delete-cloud).WP_DEBUG is on (filter omnioffloader_log_provider_errors); they are always recorded on the attachment.omnioffloader_should_apply_retention filter no longer show as “needs updating” forever.omnioffloader_media_block_names to register third-party media blocks.omnioffloader_after_offload action fires again after an attachment is offloaded and verified..omnioffloader-site.json file. Before, two sites using the same folder overwrote each other’s files, and Mirror Delete on one site deleted files the other still served. Settings now refuses a folder another site uses. A site that finds another site’s marker in its folder switches to Safe mode and stops uploading and deleting. It shows a banner with Choose a Path Prefix and This folder belongs to this site. Bulk Offload and retention runs stop with a clear message instead of failing item by item. Test Connection warns about a taken folder, wp omnioffloader status reports it, and a confirmed domain move (“This is the live site”) takes the folder’s claim along. The folder is checked on the first upload or delete after an update or settings change, then once a day. Developers can turn the check off with the omnioffloader_check_folder_claim filter.New Features & Batch Controls
limit parameter: registered sanitized and validated limit parameter on POST /omnioffloader/v1/offload/bulk and POST /omnioffloader/v1/bring-back/bulk.--limit=<number>: added --limit=<number> option to wp omnioffloader restore matching wp omnioffloader offload --limit=<number>, enabling batch restores from the terminal.Reliability & Caching Fixes
no-store, no-cache, must-revalidate, max-age=0, Pragma: no-cache, Expires: 0, and X-LiteSpeed-Cache-Control: no-cache) to all plugin REST endpoints.DONOTCACHEPAGE constant definition and litespeed_can_cache / breeze_can_cache bypass filters to prevent web-server level caching of dynamic REST routes._t=${Date.now()}) and cache: 'no-store' to all API polling and data fetch calls, preventing browsers, edge proxies, and reverse proxies from serving stale HTTP 200 responses.wp_cache_delete) for queue state options prior to reading, ensuring multi-worker Redis and Memcached environments observe real-time bulk progress without delay.transient) and fallback options table entries.?refresh=1) to /core/stats and /bring-back/preflight, allowing immediate post-run verification directly from the database.UI & Experience Improvements
%d items / %d item) and consistent badge styling.New Features & Enhancements
post.php) with cloud storage status, provider, bucket, offloaded date, CDN status, and one-click actions.AsyncUploadProcessor to offload new uploads in the background without delaying server responses.--limit=<number> to wp omnioffloader offload for running bulk jobs in manageable chunks.Reliability & Fixes
AbstractBulkProcessor): claims items before processing so a worker killed by host time limits drops the item instead of getting stuck in an infinite retry loop.Performance & Optimizations
document.hidden) to pause polling and conserve resources when browser tabs are inactive.wp omnioffloader offload, wp omnioffloader restore, and wp omnioffloader status.