Description
When you pull a production database into a staging or local environment, every media URL points at a file you didn’t copy — pages render with broken images and dead file links. Divine Apparitions Uploads Proxy intercepts the request for any missing uploads file and resolves it against a configured production Origin, so pages render with real media without syncing the entire uploads directory.
Because it works at the request level — hooking template_redirect when the web server routes a missing file to index.php (nginx try_files, used by DDEV, Lando, and Pantheon) — it catches every missing upload, including images embedded directly in post content, size derivatives, and srcset candidates, not just the URLs WordPress generates for attachments.
It resolves a missing file in one of two modes:
- Download mode (default): streams the file from the Origin, saves it into the local uploads directory, and serves it. Every later request is served by the web server, so your local site accumulates exactly the subset of media your tests actually touch — never the whole uploads folder.
- Hotlink mode (opt-in): issues a temporary redirect to the file on the Origin, writing nothing locally.
Configuration lives in wp-config constants / environment variables (with a database-option fallback), so it survives every database pull and configures itself hands-free in CI. The plugin is inert on production and stays off until an Origin is configured.
Features:
- Request-level interception — resolves content-embedded images, derivatives, and
srcset, not just attachment URLs. - Download or Hotlink mode, chosen per environment.
- Optional Basic Auth for fetching from a locked Test/Dev Origin.
- Negative cache so a file genuinely missing on the Origin stops re-hitting it, while transient errors (5xx/timeout) retry on the next request.
- Write hardening: executable file types are refused and paths are contained to the uploads directory.
- Diagnostics settings page showing the effective config and its source, the counters, and a “test Origin connection” button.
wp uploads-proxyWP-CLI command (status/clear-cache) for scripting setup and reset in CI.- Inert on production; off until an Origin is configured.
Installation
- Install the plugin from the Plugins Add New screen, or upload the
divine-apparitions-uploads-proxydirectory to/wp-content/plugins/. - Activate the plugin through the Plugins menu in WordPress.
- Configure the Origin and mode via a
wp-configconstant or environment variable (recommended — these survive a production database pull and work hands-free in CI), or as a fallback from Settings Uploads Proxy.
FAQ
-
Does this download files to my local environment?
-
In Download mode (the default), yes — each missing file is fetched from the Origin once, saved into your local uploads directory, and served; every later request is served directly by the web server. In Hotlink mode nothing is written locally — the browser is redirected to the file on the Origin.
-
How do I configure it so my settings survive a database pull?
-
Set the Origin (and mode, and optional Basic Auth) in a
wp-configconstant or an environment variable. Configuration resolves in the order constant environment variable database option off, so constants/env always win over anything a pulled production database might carry. The settings page is only a fallback for when no constant or env var is set. -
Will it run on production?
-
No. When
wp_get_environment_type()returnsproduction, the proxy stays inactive. -
I’m on Apache and nothing happens. Why?
-
Request interception needs the web server to route a missing file to
index.php. On nginx (DDEV, Lando, Pantheon) this always happens. On Apache it only happens with pretty permalinks enabled — the plugin shows an admin notice for this case. Enable pretty permalinks at Settings Permalinks. -
My SVGs are broken in Download mode. Why?
-
Download mode only saves files whose type WordPress recognises on a front-end request, and SVG is usually not on that list (the SVG Support plugin registers it only for logged-in uploaders). Either add a one-line
uploads_proxy_is_allowed_filefilter to opt SVG in (see the readme/README), or switch to Hotlink mode, which redirects to the Origin and applies no write gate. -
Large files time out in Download mode. Can I fix that?
-
The whole file is buffered in memory, so the default Origin timeout is a short 15 seconds. Raise it with the
uploads_proxy_origin_timeoutfilter, or use Hotlink mode to avoid downloading large files locally at all.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“Divine Apparitions Uploads Proxy” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “Divine Apparitions Uploads Proxy” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
0.11.1
- Maintenance release: version bump only, no functional changes.
0.11.0
- Renamed the plugin to Divine Apparitions Uploads Proxy (slug and text domain
divine-apparitions-uploads-proxy) for the WordPress.org directory; internal option keys, filters, theX-Uploads-Proxyheader, and thewp uploads-proxyCLI command are unchanged. - Added an
uploads_proxy_is_allowed_filefilter so types WordPress omits on the front end (notably SVG) can be proxied in Download mode; executables can never be re-enabled through it. - Added an
uploads_proxy_origin_timeoutfilter to adjust the outbound Origin timeout (default 15s) for large media on a slow link. - Fixed: a Download-mode Miss is served with HTTP 200 (was 404 on the first request).
- Fixed: a Hotlink-mode Miss returns a real 302 even behind a page cache that tracks status through
status_header()(e.g. Pantheon Advanced Page Cache); all responses now set status viastatus_header(). - Fixed: percent-encoded filenames (e.g. a space) are decoded before the local lookup, so the file is saved under its real name instead of a junk “%20” copy that is re-proxied every request; also hardens the scope against encoded
../and null bytes. - Added a settings-screen notice when the proxy is enabled but the environment type is
production.
0.10.0
- Clean up after the plugin on uninstall: deleting the plugin removes its settings option, both counters (downloaded total and Negative-cache size), and every Negative-cache transient — on every site of a multisite network. Downloaded media in the uploads directory is never deleted, so you keep any files you pulled in.
0.9.0
- Add an admin notice for the Apache plain-permalinks edge case: when the proxy is active on Apache without pretty permalinks (so interception can’t fire), a notice explains that pretty permalinks are required. Never shown on nginx, with pretty permalinks, when inert, or on production.
0.8.0
- Add the
wp uploads-proxyWP-CLI command.statusreports the active state, effective Origin, mode and each value’s source, and both counters (--format=table|json|yaml|csv).clear-cacheclears the Negative cache and resets the counters without deleting downloaded media. Registered only under WP-CLI.
0.7.0
- Replace the plain settings form with a diagnostics-first Settings Uploads Proxy page: status panel with the effective Origin/mode/Basic-Auth each labelled by source, the downloaded and Negative-cache counters, and a “test Origin connection” button (graded reachable on a 2xx response only).
- Fields are editable only when no constant/env var overrides them; an overridden field is shown read-only with its source. The Basic Auth password is write-only — never rendered into the page — and an empty save no longer blanks the stored password.
0.6.0
- Add Hotlink mode: when
mode = hotlink, a Miss issues a302temporary redirect (never301) to the file on the Origin with anX-Uploads-Proxy: hotlinkheader, writing nothing locally. Download mode remains the default.
0.5.0
- Add the Miss-fallback + Negative cache. An Origin
404/410serves a local404(X-Uploads-Proxy: negative) and records a short-lived transient so repeat Misses short-circuit without re-hitting the Origin; an Origin5xx/timeout serves404without caching so the next request retries.
0.4.0
- Harden the download writer: a two-layer gate denies executable extensions (
.php,.phtml,.cgi, …) and admits only WordPress-permitted MIME types, so a disallowed type from the Origin returns a local404and writes nothing. Reinforces path containment and host-fixed Origin fetch.
0.3.0
- Add the request-interception walking skeleton (ADR-0001): on a Miss for a missing Uploads path, Download mode fetches the file from the Origin, atomically saves it into the local uploads directory, and serves it with an
X-Uploads-Proxy: downloadheader. Replaces the URL-rewriting media proxy. - Inert on production and until an Origin is configured. Stands up a
@wordpress/envintegration test harness that boots real WordPress with a mocked Origin.
0.2.0
- Add a configuration resolver that resolves the Origin, mode, and Basic Auth in the order constant environment variable database option off, reporting each value’s source.
- Reshape the stored settings to an enabled flag, Origin URL, mode (Download/Hotlink), and Basic Auth credentials. The plugin stays off until an Origin is configured.
0.1.0
- Initial scaffold: settings page, URL-rewriting media proxy, and tooling.