Title: OmniOffloader — Multi-Cloud Media Offload &amp; CDN
Author: Huzaifa Al Mesbah
Published: <strong>ستمبر 7, 2026</strong>
Last modified: اکتوبر 10, 2026

---

Search plugins

![](https://ps.w.org/omnioffloader/assets/banner-772x250.png?rev=3685275)

![](https://ps.w.org/omnioffloader/assets/icon-256x256.png?rev=3685275)

# OmniOffloader — Multi-Cloud Media Offload & CDN

 By [Huzaifa Al Mesbah](https://profiles.wordpress.org/huzaifaalmesbah/)

[Download](https://downloads.wordpress.org/plugin/omnioffloader.0.1.5.zip)

 * [Details](https://bcc.wordpress.org/plugins/omnioffloader/#description)
 * [Reviews](https://bcc.wordpress.org/plugins/omnioffloader/#reviews)
 *  [Installation](https://bcc.wordpress.org/plugins/omnioffloader/#installation)
 * [Development](https://bcc.wordpress.org/plugins/omnioffloader/#developers)

 [Support](https://wordpress.org/support/plugin/omnioffloader/)

## Description

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](https://omnioffloader.vercel.app/).

#### See it in action

OmniOffloader in 2 minutes:

The full walkthrough — install, connect a bucket, serve from your CDN, Bulk Offload,
WP-CLI, Media Library, Bring Back and every other feature, step by step:

#### Supported cloud storage providers

 * **Amazon S3**
 * **Cloudflare R2**
 * **DigitalOcean Spaces**
 * **Backblaze B2**
 * **Wasabi**
 * **Any S3-compatible storage** — MinIO, Storj, OVHcloud, Linode, Scaleway and 
   others, through the generic option where you supply your own endpoint and region,
   and give it your own display name.

#### Key features

 * **Automatic offloading** — new uploads go to the cloud in the background, so 
   the upload screen never waits on a cloud transfer.
 * **Bulk offload for existing media** — process the whole library or a set number
   of attachments (5, 10, 25, 50, 100 or any number), with a live progress bar, 
   activity log and a Cancel button.
 * **Large libraries, much faster** — `wp omnioffloader offload --all --concurrency
   =32` (up to 64) uploads many files at the same time from WP-CLI on a VPS or dedicated
   server. Bring Back, retention and move take `--concurrency` too.
 * **Adjustable transfer speed** — offload your existing, not-yet-offloaded media
   library and bring it back faster by moving 1, 3 or 6 files at the same time, 
   or your own number from 1 to 10. Every setting runs inside a single PHP process,
   so faster never means more server processes.
 * **Content URL rewriting** — images, galleries, video, audio, file, cover and 
   media-text blocks, Classic Editor media tags and audio/video shortcodes are all
   served from the cloud, without editing post content.
 * **Serve from your CDN** — media is delivered from your custom domain or CDN edge,
   not your origin server. Not ready yet? Turn off **Serve Media from Cloud** to
   offload now and keep loading media from your server, then switch over with one
   click.
 * **Three retention policies** — keep every local copy, delete only generated thumbnails(
   Smart Local Cleanup), or move everything to the cloud (Full Cloud Migration).
 * **Apply a new policy to old media** — change the retention policy later and apply
   it to media you already offloaded, from the Tools screen or `wp omnioffloader
   retention`. Every file is checked in the cloud before its local copy is deleted,
   many attachments at once.
 * **Bring Back** — restore media from the cloud to your server, per file or in 
   bulk, with a disk-space preflight so you know what it needs before it starts.
   Deleting the cloud copy afterwards is optional and off by default.
 * **Media Library integration** — a status column, grid view badges, a meta box
   on the edit screen, row actions and bulk actions for Offload and Bring Back.
 * **Mirror Delete** — deleting an attachment in WordPress removes its cloud copies
   too (on by default for new installs; never on a staging or dev copy).
 * **Object versioning and path prefix** — add a timestamp segment to object keys
   so CDN caches never serve a stale file, and store objects under a folder of your
   choice. Change the folder later and move existing media into it from Tools or
   with `wp omnioffloader move`.
 * **WP-CLI** — offload, restore, apply retention, move media to the current folder
   and check status from the terminal. Long jobs keep running after you close the
   terminal when started with `nohup`, and `wp omnioffloader stop` ends them from
   anywhere. A full command reference is on the Tools screen.
 * **Credentials in wp-config.php** — define keys as PHP constants instead of storing
   them in the database; the settings screen locks those fields.

#### Built for every host — shared plans to dedicated servers

OmniOffloader is designed to run on a small shared hosting plan just as well as 
on a VPS.

 * **One PHP process, low memory.** Bulk jobs run in the background, one short pass
   at a time. Faster transfer speeds upload several files side by side over the 
   same connection instead of starting extra workers.
 * **You choose the pace.** Choose **Low** on a small shared plan to upload one 
   file at a time, **Balanced** (the default) for most sites, or **Fast** / **Custom**
   on a VPS or dedicated server. WP-CLI uses the same setting.
 * **Large files in parts.** Files above 64 MB are uploaded in chunks, so a dropped
   connection costs one chunk instead of the whole transfer, and files beyond 5 
   GB are supported.
 * **No stuck jobs.** A file that your host’s time limit cuts short is reported 
   and skipped instead of retried forever, and a broken connection stops the run
   after 10 failures in a row with an explanation.
 * **Works where loopback requests are blocked.** If your host blocks WordPress’s
   internal background requests, the open admin page keeps the job moving instead.
 * **Caching-friendly.** Progress stays live under LiteSpeed Cache, Breeze, Redis
   and Memcached.

#### Safe by design

 * A local file is never deleted until its upload is confirmed in your bucket.
 * A cloud file is never deleted until Bring Back has confirmed the local copy —
   and only if you turned that option on.
 * Restores write to a temporary file first and move it into place, and never write
   outside your uploads folder.
 * Only one bulk job (offload, Bring Back, retention or move) runs at a time, whether
   it was started from the admin screens, the Media Library or WP-CLI.
 * Moving media between your server and the cloud is limited to administrators. 
   Other users keep their normal rights: they upload and delete their own media.
 * Access keys are never shown in the browser or written to logs.
 * Safe mode for staging, development and local copies: a copy of your site never
   uploads to or deletes from the live site’s cloud storage.
 * Several sites can share one bucket and one CDN address, each in its own folder.
   A site never uploads to or deletes from a folder another site already uses.

#### For developers

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`, `omnioffloader_free_disk_space`, `omnioffloader_cpanel_quota_file`,`
omnioffloader_check_folder_claim`.

Actions: `omnioffloader_before_offload`, `omnioffloader_after_offload`, `omnioffloader_before_restore`,`
omnioffloader_after_restore`, `omnioffloader_transfer_heartbeat`.

REST API namespace: `omnioffloader/v1`. WP-CLI: `wp omnioffloader`. Full reference
with examples: [Hooks](https://omnioffloader.vercel.app/developers/hooks/) and [WP-CLI](https://omnioffloader.vercel.app/wp-cli/).

#### Why offload media to cloud storage?

 * **Reclaim disk space** — media is usually the bulk of a WordPress install, and
   object storage costs a fraction of hosting disk.
 * **Faster media delivery** — files served from a CDN edge load closer to your 
   visitors.
 * **Lighter backups and migrations** — a site without gigabytes of uploads is far
   quicker to back up and move.
 * **No lock-in** — Bring Back reverses the whole thing whenever you want.

#### Licensing note

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.

### External services

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:

 * **Amazon S3** (Amazon Web Services) — [Service Terms](https://aws.amazon.com/service-terms/),
   [Privacy Notice](https://aws.amazon.com/privacy/)
 * **Cloudflare R2** (Cloudflare) — [Terms](https://www.cloudflare.com/terms/), 
   [Privacy Policy](https://www.cloudflare.com/privacypolicy/)
 * **DigitalOcean Spaces** (DigitalOcean) — [Terms of Service](https://www.digitalocean.com/legal/terms-of-service-agreement),
   [Privacy Policy](https://www.digitalocean.com/legal/privacy-policy)
 * **Backblaze B2** (Backblaze) — [Terms of Service](https://www.backblaze.com/company/terms.html),
   [Privacy Policy](https://www.backblaze.com/company/privacy.html)
 * **Wasabi** (Wasabi Technologies) — [Customer Agreement](https://wasabi.com/legal/customer-agreement),
   [Privacy Policy](https://wasabi.com/legal/privacy-policy)
 * **Any S3-compatible storage** — the service at the endpoint you enter; its own
   terms and privacy policy apply.

## Screenshots

[⌊Dashboard — Real-time cloud provider status, media offload stats, and quick actions.⌉⌊
Dashboard — Real-time cloud provider status, media offload stats, and quick actions
.⌉[

Dashboard — Real-time cloud provider status, media offload stats, and quick actions.

[⌊Cloud Provider & Credentials — Multi-cloud provider selection (Cloudflare R2, 
AWS S3, Wasabi, DigitalOcean, Backblaze B2, S3-Compatible) with instant "Test Connection"
verification.⌉⌊Cloud Provider & Credentials — Multi-cloud provider selection (Cloudflare
R2, AWS S3, Wasabi, DigitalOcean, Backblaze B2, S3-Compatible) with instant "Test
Connection" verification.⌉[

Cloud Provider & Credentials — Multi-cloud provider selection (Cloudflare R2, AWS
S3, Wasabi, DigitalOcean, Backblaze B2, S3-Compatible) with instant “Test Connection”
verification.

[⌊Retention & Delivery Policies — Flexible local retention policies (Retain Local,
Smart Cleanup, Full Migration) and Serve Media from Cloud, followed by Transfer 
Speed, Mirror Delete, Object Versioning, and custom path prefixes.⌉⌊Retention & 
Delivery Policies — Flexible local retention policies (Retain Local, Smart Cleanup,
Full Migration) and Serve Media from Cloud, followed by Transfer Speed, Mirror Delete,
Object Versioning, and custom path prefixes.⌉[

Retention & Delivery Policies — Flexible local retention policies (Retain Local,
Smart Cleanup, Full Migration) and Serve Media from Cloud, followed by Transfer 
Speed, Mirror Delete, Object Versioning, and custom path prefixes.

[⌊Bulk Offload — Library counts, All Local Media or a custom batch with presets,
the Start button, and a "Run this job from WP-CLI" panel.⌉⌊Bulk Offload — Library
counts, All Local Media or a custom batch with presets, the Start button, and a "
Run this job from WP-CLI" panel.⌉[

Bulk Offload — Library counts, All Local Media or a custom batch with presets, the
Start button, and a “Run this job from WP-CLI” panel.

[⌊Zero-Lock-In Bring Back (Restore) — Safely download offloaded media back to your
local server with automatic disk space pre-flight checks and atomic restore.⌉⌊Zero-
Lock-In Bring Back (Restore) — Safely download offloaded media back to your local
server with automatic disk space pre-flight checks and atomic restore.⌉[

Zero-Lock-In Bring Back (Restore) — Safely download offloaded media back to your
local server with automatic disk space pre-flight checks and atomic restore.

[⌊WordPress Media Library Integration — Dedicated cloud offload status column, offload
state filter, contextual row actions, and native bulk offload/restore actions.⌉⌊
WordPress Media Library Integration — Dedicated cloud offload status column, offload
state filter, contextual row actions, and native bulk offload/restore actions.⌉[

WordPress Media Library Integration — Dedicated cloud offload status column, offload
state filter, contextual row actions, and native bulk offload/restore actions.

[⌊Apply Retention Policy to Existing Media — Tools screen to synchronize existing
media with updated retention policies, including pre-flight storage estimates and
batch scopes.⌉⌊Apply Retention Policy to Existing Media — Tools screen to synchronize
existing media with updated retention policies, including pre-flight storage estimates
and batch scopes.⌉[

Apply Retention Policy to Existing Media — Tools screen to synchronize existing 
media with updated retention policies, including pre-flight storage estimates and
batch scopes.

[⌊Safe Mode — A staging, development or local copy is recognised automatically and
stops writing to the live site's cloud storage, with a "This is the live site" button
for a real domain move.⌉⌊Safe Mode — A staging, development or local copy is recognised
automatically and stops writing to the live site's cloud storage, with a "This is
the live site" button for a real domain move.⌉[

Safe Mode — A staging, development or local copy is recognised automatically and
stops writing to the live site’s cloud storage, with a “This is the live site” button
for a real domain move.

[⌊Move Media to the Current Folder — After a Path Prefix change, move media from
earlier folders into the current one; within the same bucket the files are copied
by your storage provider, with nothing downloaded.⌉⌊Move Media to the Current Folder—
After a Path Prefix change, move media from earlier folders into the current one;
within the same bucket the files are copied by your storage provider, with nothing
downloaded.⌉[

Move Media to the Current Folder — After a Path Prefix change, move media from earlier
folders into the current one; within the same bucket the files are copied by your
storage provider, with nothing downloaded.

[⌊WP-CLI Reference — Every command on the Tools screen with examples and copy buttons,
plus how to run a long job in the background, watch it and stop it.⌉⌊WP-CLI Reference—
Every command on the Tools screen with examples and copy buttons, plus how to run
a long job in the background, watch it and stop it.⌉[

WP-CLI Reference — Every command on the Tools screen with examples and copy buttons,
plus how to run a long job in the background, watch it and stop it.

## Installation

 1. Install the plugin from **Plugins  Add New**, or upload the `omnioffloader` folder
    to `/wp-content/plugins/`.
 2. Activate it through the **Plugins** screen.
 3. Open **OmniOffloader  Settings**.
 4. Pick your storage provider, enter its credentials and your Custom Domain / CDN 
    URL, then click **Test Connection**.
 5. Choose a retention policy. Start with **Retain Local Files** — it keeps every local
    copy while you confirm everything serves correctly.
 6. Choose a **Transfer Speed** that suits your hosting (Balanced is a good start).
 7. Open **OmniOffloader  Offload** and start a bulk offload for your existing media.
    New uploads are offloaded automatically from now on.

## FAQ

### Which cloud storage providers are supported?

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.

### How do I configure Cloudflare R2?

 1. In the Cloudflare dashboard, go to **R2** and create a bucket.
 2. In the bucket’s **Settings**, connect a **Custom Domain** (for example `https://
    media.yourdomain.com`) or enable the public `r2.dev` URL, so your files can be 
    served publicly.
 3. Back on the R2 overview page, open **Manage R2 API Tokens**, create a token with**
    Object Read & Write** permission, and copy the Access Key ID and Secret Access 
    Key.
 4. Copy the bucket’s **S3 API** endpoint (`https://<account-id>.r2.cloudflarestorage.
    com`) from the bucket settings.
 5. In OmniOffloader Settings, select **Cloudflare R2** and enter the Access Key ID,
    Secret Access Key, Endpoint URL, Bucket Name and your custom domain, then click**
    Test Connection**.

Full guide: [omnioffloader.vercel.app/providers/cloudflare-r2/](https://omnioffloader.vercel.app/providers/cloudflare-r2/)

### How do I configure Amazon S3?

 1. In the AWS console, create an S3 bucket in your preferred region.
 2. In IAM, create a user with programmatic access and a policy that allows reading
    and writing objects in that bucket. Create an access key and copy the Access Key
    ID and Secret Access Key.
 3. To serve media publicly, allow public `s3:GetObject` on the bucket with a bucket
    policy, or put an **Amazon CloudFront** distribution in front of it.
 4. In OmniOffloader Settings, select **Amazon S3** and enter the keys, Bucket Name,
    Region (for example `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://omnioffloader.vercel.app/providers/amazon-s3/)

### How do I configure DigitalOcean Spaces?

 1. In the DigitalOcean control panel, create a Space and, if you want, enable its 
    built-in CDN.
 2. Create a **Spaces access key** and copy the key and secret.
 3. Note the region endpoint (for example `https://nyc3.digitaloceanspaces.com`) and
    region (`nyc3`).
 4. In OmniOffloader Settings, select **DigitalOcean Spaces** and enter the keys, Endpoint
    URL, Region, Space name and your CDN or custom domain.

Full guide: [omnioffloader.vercel.app/providers/digitalocean-spaces/](https://omnioffloader.vercel.app/providers/digitalocean-spaces/)

### How do I configure Backblaze B2?

 1. In the Backblaze B2 console, create a bucket and set **Files in Bucket are** to**
    Public** so media can be viewed in browsers.
 2. Note the bucket’s S3 Endpoint (for example `https://s3.us-east-005.backblazeb2.
    com`) and its region (`us-east-005`).
 3. Under **Application Keys**, add a key with **Read and Write** access to the bucket,
    and copy the `keyID` and `applicationKey`.
 4. In OmniOffloader Settings, select **Backblaze B2** and enter the Application Key
    ID, Application Key, Endpoint URL, Region and Bucket Name. Leave the CDN URL blank
    to serve directly from Backblaze, or enter your CDN domain.

Full guide: [omnioffloader.vercel.app/providers/backblaze-b2/](https://omnioffloader.vercel.app/providers/backblaze-b2/)

### How do I configure Wasabi?

 1. In the Wasabi console, create a bucket and note its region (for example `us-east-
    1`).
 2. Create an access key and copy the Access Key ID and Secret Access Key.
 3. Make the files publicly readable with a bucket policy, or serve them through a 
    CDN in front of the bucket.
 4. In OmniOffloader Settings, select **Wasabi** and enter the keys, Bucket Name, Region
    and your CDN or custom domain.

Full guide: [omnioffloader.vercel.app/providers/wasabi/](https://omnioffloader.vercel.app/providers/wasabi/)

### How do I configure Storj or other S3-compatible storage?

 1. In the Storj console, create a bucket and open **Access  Create S3 Credentials**.
    Copy the Access Key and Secret Key.
 2. Share the bucket publicly (**Objects  your bucket  Share**) and copy the link-sharing
    URL, for example `https://link.storjshare.io/s/<KEY>/<BUCKET>`. Replace `/s/` with`/
    raw/`.
 3. In OmniOffloader Settings, select **Any S3-Compatible Storage**.
 4. Set the S3 Endpoint URL to `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/](https://omnioffloader.vercel.app/providers/s3-compatible/)

### Which Transfer Speed should I choose?

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:

 * **Low** — one file at a time. The lightest option for small shared hosting plans.
 * **Balanced** — 3 files at a time. The default, and right for most sites.
 * **Fast** — 6 files at a time, for a VPS or dedicated server.
 * **Custom** — any number from 1 to 10.

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. For a one-off WP-CLI run on a VPS, `--concurrency
=32` (up to 64) on `offload`, `restore`, `retention` or `move` goes beyond it for
that run only.

### How long does a bulk offload take, and can I close the browser tab?

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.

### Will offloading break my existing image URLs?

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.

### Can I move my media back to my server later?

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.

### What happens to my images if I deactivate the plugin?

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.

### I copied my live site to staging or a local dev site. Can it damage the live site’s media?

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**:

 * the site address changed from the one recorded as live (stored as a fingerprint,
   so migration tools’ search-and-replace can’t hide the change),
 * WordPress reports a staging, development or local environment (`WP_ENVIRONMENT_TYPE`,
   set by many managed hosts and local tools), or
 * the site runs on a local address such as `localhost`, `*.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.

### Can several separate sites share one bucket and one CDN address?

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.

### Do I have to delete my local files?

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.

### I changed the retention policy. Why are old files still on my server?

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. For a large library on a VPS, `wp omnioffloader retention--
concurrency=32 --yes` checks 32 attachments at once.

### Why do I need a custom domain or CDN URL?

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.

### Can I offload now and switch to the CDN later?

Yes. With the **Retain Local Files** policy, turn off **Serve Media from Cloud**
in **Settings  Retention Policy**. Media is still offloaded to your bucket, but 
your site keeps loading it from your own server. When your CDN is ready, turn it
on: every offloaded file switches over at once, with nothing uploaded again. Clear
your page cache after changing it. The cleanup policies delete local files, so with
them media always loads from the cloud.

### Can I keep my access keys out of the database?

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.

### Can I run it from WP-CLI?

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 offload --all --concurrency=32
    wp omnioffloader restore --all [--limit=<number>] [--delete-cloud] [--dry-run] [--concurrency=<number>]
    wp omnioffloader retention [--policy=<0|1|2>] [--dry-run] [--format=json] [--concurrency=<number>]
    wp omnioffloader move --all [--keep-old] [--dry-run]
    nohup wp omnioffloader offload --all > ~/offload.log 2>&1 &
    wp omnioffloader status
    wp omnioffloader stop
    ```

Start a long job with `nohup … &` (as above) to keep it running after you close 
the terminal; `status` shows its progress and `stop` ends it from any terminal. 
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 commands 
use your Transfer Speed setting unless you pass `--concurrency`.

### How can I offload a very large library faster?

Run the offload from WP-CLI on your server with more files at once: `wp omnioffloader
offload --all --concurrency=32`, up to 64. The admin screens stay at 10 at most,
because they run inside web requests. Try a short run first (`--limit=500`) and 
time it, then start the full run with `nohup … &` so it keeps going after you close
the terminal.

### How do I follow a long WP-CLI run?

Start it in the background with a log file in your home folder: `nohup wp omnioffloader
offload --all > ~/offload.log 2>&1 &`. The answer `[1] 12345` is the job and process
number, not an error. Follow the progress with `tail -f ~/offload.log` (Ctrl+C only
stops watching, not the job) or `wp omnioffloader status`; the log gets a timestamped
line every 25 attachments, so you can work out the speed and the time left. Stop
it with `wp omnioffloader stop` and run the same command again to continue. Step-
by-step guide: [Long runs and log files](https://omnioffloader.vercel.app/wp-cli/long-runs/).

### Who can offload or bring back media?

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.

### What about very large videos or files?

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.

### Does it work with caching plugins and object caches?

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.

### Does this plugin work on multisite?

Yes, per site. Each site in a network has its own settings, credentials and background
queues. Only a network administrator can point a provider at a private or local 
endpoint address. Multisite has not had a dedicated test pass yet, so test on a 
staging network first.

### I changed the Path Prefix. What happens to media I already offloaded?

It stays in its old folder and keeps working. To move it into the new folder, run`
wp omnioffloader move --all` (fastest) or use **Tools  Move Media to the Current
Folder**. Within the same bucket your storage provider copies the files, so nothing
is downloaded.

## Reviews

![](https://secure.gravatar.com/avatar/6b16b41301e0e27abe50b08f308894664ce3a79e5906c9c8e80b5e2558854218?
s=60&d=retro&r=g)

### 󠀁[Solid, well-engineered offloader](https://wordpress.org/support/topic/solid-well-engineered-offloader/)󠁿

 [Shazzad Hossain Khan](https://profiles.wordpress.org/sajib1223/) اکتوبر 10, 2026

Setup was straightforward: enter credentials, test connection, pick a retention 
policy. New uploads and all their thumbnails were in the bucket within seconds, 
and image URLs and srcset are rewritten on render with no search-replace in the 
database. Bring Back and the retention policies do exactly what they say, and the
WP-CLI commands with dry-run are a nice touch for larger libraries. As a developer
I appreciated the clean code: proper permission checks, prepared queries, credentials
can live in wp-config.php, and nothing phones home. Uninstall removed everything
cleanly. Impressive for an early release.

 [ Read all 1 review ](https://wordpress.org/support/plugin/omnioffloader/reviews/)

## Contributors & Developers

“OmniOffloader — Multi-Cloud Media Offload & CDN” is open source software. The following
people have contributed to this plugin.

Contributors

 *   [ Huzaifa Al Mesbah ](https://profiles.wordpress.org/huzaifaalmesbah/)

“OmniOffloader — Multi-Cloud Media Offload & CDN” has been translated into 1 locale.
Thank you to [the translators](https://translate.wordpress.org/projects/wp-plugins/omnioffloader/contributors)
for their contributions.

[Translate “OmniOffloader — Multi-Cloud Media Offload & CDN” into your language.](https://translate.wordpress.org/projects/wp-plugins/omnioffloader)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/omnioffloader/), check
out the [SVN repository](https://plugins.svn.wordpress.org/omnioffloader/), or subscribe
to the [development log](https://plugins.trac.wordpress.org/log/omnioffloader/) 
by [RSS](https://plugins.trac.wordpress.org/log/omnioffloader/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 0.1.5

**Fixes**

 * Editors: media that is no longer on the server (Smart Local Cleanup, Full Cloud
   Migration) now shows while you edit, in the block editor and the classic editor,
   including video and audio shortcodes and restored autosaves or revisions. Editors
   load it from the cloud like the front end does.
 * Saving a post stores your site’s own URLs for offloaded media, including media
   you just inserted, so content keeps working after a Bring Back or a change of
   CDN domain.

#### 0.1.4

**Serve Media from Cloud**

 * New setting in **Settings  Retention Policy**: with **Retain Local Files**, turn
   off **Serve Media from Cloud** to keep offloading media while your site still
   loads it from your own server, for example while you set up your CDN. Turn it
   on and every offloaded file switches to your cloud storage or CDN at once, with
   no re-upload.
 * Smart Local Cleanup and Full Cloud Migration delete local files, so with those
   policies media always loads from the cloud. Files an earlier policy already removed
   keep loading from the cloud until they are downloaded again, so turning serving
   off never breaks an image.

**Move media to the current folder**

 * You can change the Path Prefix while media is offloaded. Settings explains that
   existing media stays in its folder and keeps working, and **Save changes** asks
   you to confirm. Once saved, Settings shows how many attachments are outside the
   current folder and how to move them: `wp omnioffloader move --all` (recommended,
   with copy buttons and a background version for large libraries) or **Move media
   in Tools**.
 * New `wp omnioffloader move`: moves media offloaded under an earlier Path Prefix
   into the current folder. Within the same bucket your storage provider copies 
   the files itself, so nothing is downloaded and your server’s files are not touched;
   old copies are deleted once the new ones are verified. Files that can’t be copied
   that way (over 5 GB, or in another bucket) go through the server. Supports `--
   dry-run`, `--ids`, `--limit`, `--keep-old` and `--concurrency` (up to 64 files
   at once).
 * New **Tools  Move Media to the Current Folder**: the same move from the admin
   screen, with a progress bar and Cancel. Shown only when some media is outside
   the current folder.
 * The OmniOffloader box on an attachment’s edit screen shows its bucket **Folder**,
   marked _Not in the current folder_ when needed. `wp omnioffloader status` shows
   the current folder and how many offloaded attachments are in other folders.

**WP-CLI: faster offloads**

 * New `wp omnioffloader offload --concurrency=<1–64>`: upload up to 64 files at
   the same time for that run, instead of the Transfer Speed setting (at most 10,
   which the admin screens keep). For a VPS or dedicated server offloading a large
   library.
 * `restore` and `retention` take `--concurrency` too. A stricter retention policy
   now checks a group of attachments in cloud storage at once (Transfer Speed on
   the Tools screen, `--concurrency` in WP-CLI), so it is much faster on large libraries;
   every file is still verified by size before deletion.
 * **Tools  Apply Retention Policy** links to its WP-CLI command, like Offload and
   Bring Back.

**WP-CLI: stop, status and long runs**

 * Long runs started with `nohup wp omnioffloader … > file.log 2>&1 &` keep going
   after you close the terminal and write a progress line every 25 attachments to
   the log. A run without a terminal that would ask for confirmation stops with 
   a message asking for `--yes`, instead of waiting for an answer.
 * New `wp omnioffloader stop` ends the running job (offload, Bring Back, retention
   or move) 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` starts with what is running now: progress, start time,
   speed, time left and expected finish, files transferred at once, log file and
   how to stop it. When nothing runs, it shows how the last WP-CLI job ended and
   the command to offload media that is still local.
 * Long runs write to the database far less often: locks are renewed every 30 seconds
   and progress is saved at most every 5 seconds, instead of several writes per 
   attachment.
 * A lock left behind by a killed run (for example after a server restart) is cleared
   by the next command on the same server, instead of blocking it for 10 minutes.
 * New documentation page [Long runs and log files](https://omnioffloader.vercel.app/wp-cli/long-runs/):
   start a big job with a log file, watch it, work out the speed and time left, 
   and what to do when it ends.

**Admin screens**

 * The WP-CLI reference on the Tools screen covers the new `move` and `stop` commands
   and how to keep a job running with `nohup`.
 * The Offload and Bring Back pages have a **Run this job from WP-CLI** panel whose**
   View command** button opens the command in the WP-CLI reference on the Tools 
   screen (recommended for libraries of 5,000+ items).
 * Every OmniOffloader screen links to the documentation: a **Documentation** link
   in the page header, **Learn more** on each section and setting, and a setup guide
   for the selected storage provider.
 * While a WP-CLI job runs, the Offload, Bring Back and Tools screens show which
   one, with its progress, speed, time left and how to follow or stop it, and their
   Start buttons wait until it finishes. They check when you open them or come back
   to the tab, and poll only while a WP-CLI job runs.
 * Each page keeps its scroll position when you switch pages and come back, and 
   links to a section open the page right at it.
 * Confirmations (Bring Back that deletes cloud copies, a bucket folder change, 
   moving media, Safe mode’s live-site and folder buttons) use the plugin’s own 
   dialog with clear button labels, instead of the browser’s OK / Cancel box.
 * Dashboard: the status no longer says “Connected & Active” just because credentials
   are saved. It shows **Active**, or **Safe mode** on a copy of the site, and says
   when your site still loads media from the server (Serve Media from Cloud off).
 * Accessibility: screen readers hear when a bulk job starts, the result of Test
   Connection, and why a Start button is disabled (now also shown as text under 
   the button); after switching pages, focus moves to the new page’s title.

**Fixes**

 * Switching to another storage provider no longer breaks media you already offloaded:
   it keeps loading from the provider it was offloaded to (through its saved settings),
   Mirror Delete deletes it there, and Move Media brings it over to the new provider.
 * The bucket, endpoint and region can no longer be changed while media is offloaded
   there, which used to break those URLs and Bring Back. Settings explains the steps:
   Bring Back, change the bucket, offload again. A region may only contain letters,
   numbers and dashes.
 * Sharing a bucket: every folder this site has used, including folders from before
   0.1.4, stays protected, and each upload or delete is checked against the folder
   it really goes to. If another site takes over an old folder, this site stops 
   writing to it and `wp omnioffloader status` warns about it.
 * Multisite: a site administrator can no longer point a provider at a private or
   local endpoint address (only a network administrator can), so a sub-site can’t
   make the server send requests into its own network.
 * Full Cloud Migration and Smart Local Cleanup: a new upload no longer reuses a
   file name that another attachment still has in your cloud storage (the original
   of a scaled image, a thumbnail size, a PDF preview or an edit backup), which 
   could overwrite that attachment’s files.
 * Bring Back with “Delete from Cloud After Restore” no longer deletes cloud files
   it did not download, such as the original WordPress keeps after you edit an image.
   Only files that are now on your server are removed from the cloud.
 * Bulk Bring Back with **Delete from Cloud After Restore** now asks for confirmation
   before it starts, as WP-CLI’s `--delete-cloud` does.
 * Bring Back (and loosening the retention policy) no longer fails for an image 
   whose original was already gone before it was offloaded, for example removed 
   by an image optimizer.
 * Safe mode: **This is the live site** now asks for confirmation before turning
   Safe mode off, since clicking it on a staging copy lets that copy write to the
   live site’s cloud storage. If it fails, the real reason is shown.
 * Cover and Media & Text blocks no longer rewrite links to other files from the
   same upload folder (another image or a PDF inside the block) to the cloud. Only
   the block’s own media is rewritten.
 * Bulk jobs: a run whose last worker was stopped by the server no longer shows “
   running” forever; it finishes on its own once it has been quiet for a minute 
   and the admin screen checks on it.
 * Bulk jobs: cancelling and immediately starting again no longer lets the cancelled
   run carry on inside the new one.
 * Background upload of new media: a large file is no longer uploaded twice at the
   same time, and an upload the server keeps stopping (time or memory limit) is 
   marked failed after three tries instead of being retried forever.
 * WP-CLI: closing the SSH window during `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.
 * WP-CLI: media the run was transferring when it was interrupted (Ctrl+C, a closed
   window, a killed process) no longer shows “Offloading…” or “Restoring…” in the
   Media Library forever. It goes back to its real status and the next run picks
   it up.
 * WP-CLI: a run started with `--force` next to another one no longer releases the
   other run’s lock when it ends, and stopping after the failure limit says whether
   the connection or the attachments are at fault.
 * WP-CLI: `wp omnioffloader retention` now stops after repeated failures when the
   storage provider can’t be reached, and stops at once when the server runs out
   of disk space, like `restore`.
 * Media Library: when Offload or Bring Back fails, the reason is shown as a notice(
   for example Safe mode, or another job running) instead of the page silently reloading;
   a failed bulk action shows it too.
 * Attachments whose file isn’t on the server (a copy of the site without its uploads,
   or files deleted outside WordPress) are now marked **File missing** instead of
   failing on every run: they are skipped before anything is uploaded, left out 
   of **Local (Ready to Offload)** and later runs, and counted on the Offload page
   and in `wp omnioffloader status`. Once the file is back, the next offload picks
   it up by itself.
 * Media Library: an item stuck on “Queued for background offload” or “Offloading…”(
   for example when thumbnail generation failed, or the background queue was cleared)
   goes back to its real status by itself once no job is running.
 * Media Library: picking Offload or Bring Back for items that have nothing to do(
   already offloaded, or already local) while a bulk job of the same kind runs no
   longer stops that job.
 * Media Library: a single Offload or Bring Back still in progress keeps its badge
   while another tab is open.
 * Media Library: status checks slow down while nothing changes (from every 1.8 
   up to every 6 seconds) and keep going after a failed check instead of freezing
   until the tab is focused again. The status shows the provider’s name (for example“
   Cloudflare R2”) instead of its internal key.
 * Uninstalling with `wp plugin uninstall --deactivate` no longer shows a PHP warning(“
   Constant OMNIOFFLOADER_DIR already defined”).
 * Settings: a save error stays visible until you change something or save again,
   and a save that stored the provider details but not the other settings says so.
   The Path Prefix field shows the folder name as it will be saved (“My Media” becomes“
   My-Media”).

Older releases: see the [full changelog](https://omnioffloader.vercel.app/changelog/).

## Meta

 *  Version **0.1.5**
 *  Last updated **1 day ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.6 or higher **
 *  Tested up to **7.1.3**
 *  PHP version ** 8.1 or higher **
 *  Languages
 * [Bengali (Bangladesh)](https://bn.wordpress.org/plugins/omnioffloader/) and [English (US)](https://wordpress.org/plugins/omnioffloader/).
 *  [Translate into your language](https://translate.wordpress.org/projects/wp-plugins/omnioffloader)
 * Tags
 * [cdn](https://bcc.wordpress.org/plugins/tags/cdn/)[cloud storage](https://bcc.wordpress.org/plugins/tags/cloud-storage/)
   [media library](https://bcc.wordpress.org/plugins/tags/media-library/)[offload](https://bcc.wordpress.org/plugins/tags/offload/)
   [s3](https://bcc.wordpress.org/plugins/tags/s3/)
 *  [Advanced View](https://bcc.wordpress.org/plugins/omnioffloader/advanced/)

## Ratings

 5 out of 5 stars.

 *  [  1 5-star review     ](https://wordpress.org/support/plugin/omnioffloader/reviews/?filter=5)
 *  [  0 4-star reviews     ](https://wordpress.org/support/plugin/omnioffloader/reviews/?filter=4)
 *  [  0 3-star reviews     ](https://wordpress.org/support/plugin/omnioffloader/reviews/?filter=3)
 *  [  0 2-star reviews     ](https://wordpress.org/support/plugin/omnioffloader/reviews/?filter=2)
 *  [  0 1-star reviews     ](https://wordpress.org/support/plugin/omnioffloader/reviews/?filter=1)

[Your review](https://wordpress.org/support/plugin/omnioffloader/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/omnioffloader/reviews/)

## Contributors

 *   [ Huzaifa Al Mesbah ](https://profiles.wordpress.org/huzaifaalmesbah/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/omnioffloader/)