=== WPX Remote Uploads ===
Contributors: wpx
Tags: wasabi, s3, cloud storage, offload media, uploads
Requires at least: 5.6
Tested up to: 6.6
Requires PHP: 7.4
Stable tag: 2.6.3
License: GPLv2 or later

Move your WordPress uploads folder to Wasabi Cloud Storage, auto-offload new
media, serve everything remotely, and download your whole library in one click.

== Description ==

WPX Remote Uploads connects your WordPress Media Library to Wasabi
(S3-compatible) cloud storage with no external dependencies — everything is
built with WordPress's own HTTP API.

Features:

* **Database Backup & Site Content Backup to Cloud / Remote Storage** — one
  click exports your database, or zips your entire site directory (core,
  plugins, themes, uploads), and uploads it to whichever cloud/remote
  storage is currently connected and active — inside a "DatabaseBackup" or
  "SiteContentBackup" folder. Uploaded privately (never public-read), with
  a history of past backups you can delete from here.
* Connect to any S3-compatible bucket with Access Key / Secret Key.
* **Selective Remote Serving** — control which media types actually load
  from remote storage vs. local hosting. Images and video default to
  remote; audio and documents default to local. Your Custom Logo and Site
  Icon always stay local regardless of category, even under True Remote
  Storage — a local copy is automatically restored the moment it's
  needed, so the exemption holds no matter which mode you're in.
  Everything still uploads to the cloud either way; this only controls
  which URL visitors are actually given.
* **Keep theme, plugin & script files local** — theme and plugin files
  themselves were never touched by this plugin, but generated CSS/JS/cache
  files that page builders and caching plugins (Elementor, WP Rocket,
  Autoptimize, etc.) sometimes write inside the uploads folder are now
  explicitly kept on local hosting even under True Remote Storage,
  instead of being swept into remote storage along with everything else.
* **One Item Per Object (Featured Image)** — serves the featured image via
  a native `<picture>` element with one candidate per screen size, so
  mobile visitors only ever consider the mobile-size file and desktop
  visitors only the desktop-size file — guaranteed by the browser's own
  media-query evaluation before any download starts, not device sniffing.
  Configurable mobile/desktop sizes and breakpoint; falls back to normal
  behavior automatically if a configured size doesn't exist for an image.
* **Admin bar notice** — a small counter in the WordPress admin/toolbar
  bar (front-end and admin) shows how many items on the current page are
  loading from remote storage. Click it for the actual list of URLs.
  Only visible to you, never to regular visitors. One toggle to disable.
* **Behavior tab fixes** — the "Delete local copy" description no longer
  references the removed One-Click Download feature (now points to Sync
  to Local instead), and Lazy Load now lives in its own always-usable
  card instead of being disabled/unclickable whenever True Remote Storage
  is on.
* **Storage sizes on the Behavior tab** — a quick local vs. remote storage
  size comparison now also appears right where you decide between them,
  not just on the Overview tab.
* **Promo buttons moved to the header** — "Buy Pro Now" and "Check All WPX
  Plugins" now sit in the top header bar, to the left of "View Logs",
  instead of a separate card on the Overview tab.
* **Updated tagline** — the header subtitle now reads "Offload, serve &
  back up your media with Remote Storage. A true WordPress 'Uploads'
  folder replacement with remote storage. Save your hosting inodes."
* **Auto-delete after upload (Migration)** — an opt-in checkbox on the
  Migrate tab that deletes each local file once it's confirmed safely on
  remote storage, freeing up hosting disk space as migration runs. A
  failed upload always keeps its local copy. Off by default — clearly
  marked "use with caution."
* **More cloud providers** — Amazon S3, DigitalOcean Spaces, and Google
  Cloud Storage now work as presets alongside Wasabi (all S3-compatible,
  so no new client code — just the right defaults for each). A dropdown
  next to the credentials fields fills in the correct endpoint/region for
  whichever you pick, or choose "Custom / Other S3-Compatible" for
  anything else.
* **Skip files that already exist remotely** — Migration now checks what's
  already on your active provider first (same name & size) and only
  uploads what's new or changed, instead of re-uploading everything on
  every run. On by default; a toggle on the Migrate tab lets you force a
  full re-upload instead.
* **Sync to Local** — the reverse of migration: pulls every file currently
  on your active storage provider down into this server's real local
  uploads folder, in small polled batches. Skips files that already match
  locally by default, or force re-download everything with one toggle.
* **Inline content images, not just featured images** — a new content
  filter rewrites images embedded directly in post/page content (not just
  the featured image) to load from remote storage, including on posts
  written before you switched over.
* **Sync history** — the Sync to Local tab shows the date and time of your
  last 10 sync runs, with a downloaded/up-to-date/failed breakdown for each.
* **True Remote Storage now actively guarantees zero local disk usage** —
  after every upload, any stray local copy is detected and removed once
  confirmed safely on remote storage (some hosting/PHP setups don't route
  every core file operation through a custom stream wrapper reliably).
  A local file is never deleted unless the remote copy is confirmed first.
* **Filenames stay exactly as uploaded** — an image's name (and therefore
  its attachment title, which WordPress derives from the filename) is
  never altered on remote upload unless a genuine duplicate already
  exists on the active provider, in which case a numeric suffix
  ("-1", "-2", etc.) is appended — the same convention WordPress already
  uses for local uploads, now guaranteed to work correctly for remote
  storage too.
* **Turn remote storage off entirely** — a third "None (Local Storage
  Only)" option alongside Wasabi and Bunny Storage in the active-provider
  selector. No provider has to stay active; local-only is a fully
  supported, first-class choice.
* **Sign up for Bunny.net or Wasabi directly from the Connection tab** —
  don't have a storage account yet? One click to either provider, with
  Bunny.net highlighted as the recommended option.
* **Lazy load remote images** — adds `loading="lazy"` to images so
  off-screen ones aren't fetched from remote storage until the visitor
  scrolls near them, cutting upfront round-trips to an external host.
  Covers both content-embedded images and gallery/template images. One
  toggle in the Behavior tab.
* **Tabs stay put after saving** — Save Settings now returns you to
  whichever tab you were on instead of always bouncing back to Overview.
* **Independent provider enable/disable** — Wasabi and Bunny Storage each
  have their own on/off toggle, separate from which one is actually in use.
  Keep both configured (e.g. one as a fallback) and switch which is active
  with a single radio choice at the top of the Connection tab.
* **Bunny Storage support** — an alternate storage provider from bunny.net,
  using Bunny's S3-compatible storage zone API. Only one storage provider is
  active at a time; switching is a single toggle. Requires a Storage Zone
  created with "Enable S3 Compatibility" turned on.
* **BunnyCDN integration** — put a BunnyCDN pull zone in front of either
  storage provider for faster delivery, following Wasabi's own official
  BunnyCDN + Wasabi integration guide. One toggle plus the pull zone
  hostname, and every public file URL uses it. **Required** when Wasabi is
  the active provider, so your bucket never needs to be public.
* **Its own admin menu** — WPX Remote Uploads gets a top-level item in the
  WordPress admin sidebar (Dashboard + Logs), no longer tucked under Media.
* **Process log** — a dedicated Logs page shows connection tests, migration
  progress, backup builds, and mode changes as they happen, with a live
  auto-refresh and a "Clear Log" button.
* **Fast, parallel migration** — files within each batch upload
  simultaneously (via curl_multi) instead of one at a time, with a
  configurable batch size (5–200 files) so you can tune speed vs. server
  load, plus quick presets (Safe / Balanced / Fast / Turbo) and a live
  files/sec readout.
* **Live dashboard** — auto-refreshes every 30 seconds: total media items,
  how many are offloaded, local uploads size, and total storage used on
  Wasabi (with a one-click "rescan bucket" button).
* **Recent activity feed** — shows the last 5 files written to Wasabi and
  the last 5 files read back from it, with size and relative time.
* **True Remote Storage mode** — registers a PHP stream wrapper so WordPress
  reads and writes every uploads-folder file directly on Wasabi. No local
  server/hosting storage is used for media once enabled.
* Optional auto-upload of every new file (and its generated thumbnails) the
  moment it's added to the Media Library.
* "Use Remote Drive for all operations" — serve offloaded media straight from
  Wasabi, so the bucket behaves like your local uploads folder.
* Optional automatic deletion of local files once safely stored on Wasabi, to
  free up server disk space.
* Clean, modern dashboard UI under WPX Remote Uploads (its own admin menu).

== Installation ==

1. Upload the `wpx-remote-uploads` folder to `/wp-content/plugins/`.
2. Activate the plugin through the 'Plugins' menu in WordPress.
3. Go to WPX Remote Uploads → Dashboard, and on the Connection tab choose
   your storage provider: enable the Wasabi card (default) or the Bunny
   Storage card — enabling one automatically disables the other.
4. Fill in that provider's credentials and click "Test Connection" to verify.
5. Optionally enable BunnyCDN in the CDN card if you want a pull zone in
   front of your storage for faster delivery (works with either provider).
6. Optionally run "Start Migration" to push your existing files to the
   active provider.
7. Enable "Auto-upload new files" and/or "Use Remote Drive for all
   operations" as desired.
8. Check the Logs page anytime to confirm what the plugin has been doing.

== Notes ==

* Requires the PHP `curl`/`openssl` extensions, bundled with virtually every
  WordPress host.
* The Backup tab (compresses a database export before uploading it to your
  storage provider) requires the PHP `zip` extension (`ZipArchive`) — also
  bundled with virtually every host, but if it's missing you'll see an
  error when starting a backup.
* Your Wasabi bucket should have public-read access enabled for objects you
  want served on the front end (the plugin uploads with a `public-read` ACL
  by default).

== True Remote Storage mode ==

Turning on "Use Remote Drive for all operations" (Behavior tab) makes Wasabi
your uploads folder at the file-system level: WordPress's own file functions
are transparently redirected to Wasabi, so nothing is written to local/hosting
storage. Before relying on it in production, be aware of:

* Each open file is buffered in memory while being read or written, so very
  large files (e.g. long videos) are bound by your host's PHP memory_limit.
* GD-based image editing is fully supported; Imagick sometimes talks to
  ImageMagick's own I/O layer directly rather than through PHP streams, which
  can bypass the wrapper for some operations.
* The very first temporary copy PHP itself creates while handling an HTTP
  upload (before WordPress code even runs) is written to the server's system
  temp directory — this is standard PHP behavior outside any plugin's control,
  and PHP deletes it automatically at the end of the request.
* Always run "Test Connection" and migrate existing files (Migrate tab)
  before switching this on for a live site, and test on staging first.

== Changelog ==

= 2.6.3 =
* Changed: Data Sharing description on the License page updated.

= 2.6.2 =
* Fix: PRO tab content (Behavior, Migrate, Sync) stayed dimmed and
  unclickable even after activating a license. The CSS rule that dims
  and disables PRO-gated content wasn't actually scoped to only apply
  when a section was gated — it fired unconditionally on every page
  load regardless of license status. Now correctly scoped so it only
  applies when the license is inactive.

= 2.6.1 =
* Fix: PRO-gated fields (Behavior, Migrate, Sync) could remain disabled
  after activating a license. The gating script now explicitly enables
  controls when PRO is active, not just disables them when it isn't.
* Removed: the "Telemetry" / "Send Test Check-in Now" diagnostic section
  on the License page.

= 2.10.3 =
* Changed: dashboard header subtitle wording updated.

= 2.10.2 =
* Fix: Site Content Backup failing immediately with "Could not reopen the
  backup zip file mid-run." The first zipping step reopened the zip file
  created moments earlier with no flags, which requires an already-fully-
  finalized archive — some PHP/libzip builds don't leave a zero-entry
  archive in a state that satisfies that on the very first batch. The
  reopen now uses the CREATE flag, so it self-heals instead of requiring
  a perfect empty file to already exist. Also now checks that each
  zip write actually succeeds (both the initial create and every batch's
  close), instead of assuming it did.

= 2.10.1 =
* Changed: replaced the scan-and-select checklist with two simple toggles
  — "Skip the Uploads folder" (on by default) and "Skip wp-config.php"
  (off by default) — removing the separate scan step and its extra moving
  parts entirely.
* Fix: Site Content Backup now starts directly from the Create Backup
  button instead of depending on a prior scan step completing.

= 2.10.0 =
* Changed: Site Content Backup now scans your site root first and shows
  every top-level file/folder in a scrollable checklist (with a Select
  All toggle) so you can choose exactly what to include, instead of
  always backing up everything under the site root.

= 2.9.0 =
* New: Site Content Backup — a second one-click backup on the Backup tab
  that zips your entire WordPress site directory (core, plugins, themes,
  uploads) and uploads it to your active cloud/remote storage inside a
  "SiteContentBackup" folder, chunked file-by-file so it won't time out on
  large sites. Uploaded privately, like the database backup.
* Changed: backup wording no longer names a specific provider ("Backup to
  Bunny Storage") — both backup types now say "Cloud / Remote Storage",
  since they already work with whichever provider (Wasabi or Bunny) is
  currently connected and active on the Connection tab.

= 2.8.0 =
* Changed: the Backup tab no longer zips the local uploads folder for
  download. It now exports your WordPress database (one click), compresses
  it, and uploads it to your active storage provider inside a
  "DatabaseBackup" folder — table-by-table so it won't time out on large
  databases. Uploaded privately (never public-read), since a database dump
  can contain sensitive data; access past backups through your storage
  provider's own dashboard, or delete them from this page.

= 2.7.1 =
* Fix: the "PRO" badges on the Behavior/Migrate/Sync tabs no longer show
  once a license is active (they were previously static and never went
  away, even though the features themselves correctly unlocked).
* Change: activating a license now redirects straight to the Dashboard
  instead of back to the License page, with a confirmation toast — so the
  newly-unlocked PRO tabs are visible immediately.

= 2.7.0 =
* New: Backup tab — builds a downloadable .zip of your local uploads
  folder in the background (chunked, so it works on hosts with strict
  execution time limits), with a history of the last 5 backups. Files are
  never exposed at a public URL — every download is authenticated.

= 2.6.1 =
* Fix: telemetry check-ins now include license_key whenever plan is
  reported as "pro" — the live marketplace API requires proof of a real,
  matching license before accepting a "pro" claim (undocumented, found by
  reviewing the marketplace source directly). Without this, check-ins from
  any licensed site were silently rejected with a 400 error the moment a
  license was activated, while free-tier check-ins worked normally.

= 2.6.0 =
* New: License → Telemetry → "Send Test Check-in Now" — sends one blocking
  check-in and shows the exact HTTP status/response (or transport error) and
  the exact payload sent, to diagnose why a site isn't showing up under
  Admin → Installs on bestplugintheme.com (network block vs. wrong
  secret/slug vs. a marketplace-side routing gap vs. reaching the server
  fine with the issue lying elsewhere).

= 2.5.0 =
* New: Behavior, Migrate Existing Files, and Sync to Local are now PRO
  features — a "PRO" badge marks these tabs, their settings/actions remain
  visible but disabled (both in the UI and, for Migrate/Sync, enforced
  server-side) until a license is activated.
* New: "Activate PRO" button on the License page and on each locked tab's
  banner, linking to https://bestplugintheme.com/product/wpx-remote-uploads.

= 2.4.0 =
* New: License screen (WPX Remote Uploads → License) — activate, validate,
  and deactivate your bestplugintheme.com license key for this site.
* New: automatic install check-in (domain, plugin version, plan, WordPress
  and PHP version) so this site shows up under Admin → Installs on
  bestplugintheme.com. Covered by our Terms & Conditions — no prompt shown.
* New: one-time, changeable opt-in to additionally share this site's admin
  email with check-ins — off by default, asked once on this plugin's own
  screens, and switchable anytime from the License page.
* New: "WPX Plugins" menu item — a quick directory of other WPX plugins.
* Updated: plugin author changed to WPX Plugin (https://wpxplugin.com).
