=== R2 Media Offload (Multi-Cloud) ===
Contributors: rise2studio
Tags: media, offload, s3, r2, cloudflare, backblaze, wasabi, digitalocean, bunny, gcs, cdn
Requires at least: 6.0
Tested up to: 6.6
Requires PHP: 8.2
Stable tag: 1.4.1
License: GPLv2 or later

Offload WordPress media to Amazon S3, Cloudflare R2, Backblaze B2, Wasabi, DigitalOcean Spaces, Bunny.net or Google Cloud Storage and serve via CDN.

== Supported providers ==
- Amazon S3
- Cloudflare R2 (zero egress)
- Backblaze B2
- Wasabi (no egress fees)
- DigitalOcean Spaces
- Bunny.net Edge Storage + CDN
- Google Cloud Storage

S3-compatible providers and Bunny.net use the built-in WordPress HTTP transport with native AWS Signature V4 / Bunny auth — no SDK or `composer install` required. Google Cloud Storage uses the official SDK.

== Features ==
- Settings page: pick a provider, set bucket/keys/region, prefix, CDN domain.
- Offload on new upload (async via Action Scheduler or WP-Cron).
- URL rewriting for attachments, image src, srcset.
- Byte-preserving: no re-encoding; offloads sidecar webp/avif variants.
- Resumable bulk migration: scan, dry-run, queue, verify, prune, restore.
- Providers & Pricing page: per-provider registration guides, pros/cons, and a live cost estimate (storage + egress + ops + hidden costs) based on your library size.
- WP-CLI commands and a logs viewer.

== Install ==
1. Activate the plugin.
2. (Google Cloud Storage only) run `composer install` to fetch `google/cloud-storage`, or use the in-admin "Install dependencies" button.
3. Open Settings → choose a provider → follow the inline setup guide → Save & Test connection.
4. Use the Migration page to bulk-offload an existing library.

== Roadmap ==
- Signed/private URLs per provider.
- Per-attachment object-key map for prune-safe remote cleanup and key rename.
- Setup wizard, auto-tuning, observability bundle.

== Changelog ==

= 1.4.1 =
* Security: a pruned attachment's file name is no longer handed to the next upload (its upload overwrote the pruned image's only copy in the bucket, and its deletion removed it); deleting an attachment keeps remote keys another attachment still uses, and forgets its own records.
* Security: regenerating metadata (any user with upload_files can trigger it for any attachment) no longer turns a pruned, offloaded image into "skipped" with broken URLs; the archived original is written once.
* Security: paths from attachment metadata must lie inside uploads — nothing outside is uploaded, pruned or restored, and symlinks are not followed.
* Security: the service-account JSON and the access key are write-only like the secret key; only service-account keys are accepted; region, R2 account ID and Bunny region can no longer redirect signed requests to another host; the connection-test message is escaped; upload tokens are redacted from logs.
* Uninstall cleans every site of a network and the options and scheduled jobs it used to leave; Composer is no longer downloaded and executed from the plugin folder.

= 1.4.0 =
* Requires PHP 8.2 (the bundled Google Cloud Storage SDK needs it). On an older PHP the plugin pauses with a notice instead of taking the site down.
* Security: the log moved from the plugin folder (publicly readable) to a protected, randomly named folder under uploads; absolute paths are no longer logged.
* Updates from plugins.rise2.studio work again.

= 1.3.0 =
* Imagify integration (archive originals, wait for Imagify), chunked prune with progress, queue hardening, migration fix.

= 1.2.0 =
* Extra uploads folders (avatars, BuddyBoss media), object-key map incl. WebP/AVIF sidecars, BuddyBoss/BuddyPress avatar URLs.

= 1.1.0 =
* Seven providers: Amazon S3, Cloudflare R2, Backblaze B2, Wasabi, DigitalOcean Spaces, Bunny.net, Google Cloud Storage.
