Table of Contents
Safely Importing Remote Images into WordPress
Correction, September 1, 2026: This article was originally written in 2011 and recommended a modified
Auto_Save_Image 2.2.2archive for WordPress 2.9.2/3.0. The old download came from a third-party file host. Its author, source, integrity, and relationship to any WordPress.org entry can no longer be verified from first-party evidence, so the link has been removed and the archive should not be installed. The historical context remains below, but the operational advice is now a current, lawful, and security-conscious media-import workflow.
What the 2011 note means now
The practical problem still exists: externally embedded images can move, disappear, or block embedding, while saving every file manually takes time. But “repost a useful article,” bulk-fetch its images, remove outbound links, and apply a common watermark is not a sound modern workflow. Importing creates another copy. Removing provenance or applying your own watermark does not create permission and may mislead readers.
The WordPress.org entry matching the old auto-save-image name is currently closed; its page says it has been unavailable since July 12, 2018, for being “Unused.” A similarly named auto-save-remote-images entry is separate: the directory says it was last updated in 2012 and tested only through WordPress 3.4.2. Surviving evidence does not establish that the old third-party ZIP was either package, and neither is a reasonable current recommendation.
Rights come before technology
Publicly reachable does not mean free to copy. Before importing, establish at least one sound basis: you created the image; the rights holder gave written permission; a clearly documented license covers the intended use; or a qualified person familiar with the relevant jurisdiction has confirmed that an exception applies. The scope must cover what you will actually do—copying, public display, modification, watermarking, commercial use, and redistribution where relevant.
Record the source page, direct file URL, creator or rights holder, license name and version, attribution requirements, acquisition date, and a snapshot of the license page or written permission. A source URL is provenance, not a license. If copyright, personality rights, trademarks, privacy, or territorial restrictions remain unclear, link to the original page or choose a clearly licensed alternative instead of importing first and asking later.
Hotlinking is not a durable substitute. Visitors still request the file from the origin, consuming its bandwidth and depending on its availability, anti-hotlinking controls, and changing terms. Do not bypass access controls, logins, paywalls, robots rules, or the origin’s embedding restrictions.
A maintainable, security-conscious workflow
1. Build a source manifest and clear the rights review
Create a manifest with one row per candidate image: source page, file URL, target post, rights basis, required credit, and responsible reviewer. Deduplicate it, and exclude avatars, tracking pixels, ads, third-party comment images, and material with an unclear purpose. An importer should accept only reviewed URLs from this manifest; it should not crawl a site and fetch everything by default.
2. Back up and test a small batch on staging
Back up both the database and the files; a database-only backup cannot restore the uploads directory. Confirm that the backup can be restored, then test a few representative items on a staging site close to production configuration. Log the before-and-after attachment IDs, post IDs, source URLs, results, and errors. Expand gradually only after human review, with a batch-level rollback path.
3. Treat every remote request as untrusted input
Prefer maintained WordPress core media and HTTP APIs over an unknown ZIP or an ad hoc arbitrary downloader. media_sideload_image() processes a remote image as an attachment and records _source_url; arbitrary URL retrieval should use the safe HTTP path that validates the initial destination and its redirects.
You still need stricter policy boundaries: an allowlist of approved HTTPS hosts; no username or password in a URL; caps on redirects, timeouts, concurrency, bytes per file, bytes per batch, and decoded pixel dimensions; and a fresh destination check on every redirect. Reject loopback, private, link-local, multicast, and cloud-metadata addresses to reduce server-side request forgery (SSRF) risk. Never disable those checks merely to make an internal URL work.
4. Validate the actual content after download
Do not trust the extension or the server-declared Content-Type. The temporary file must pass WordPress checks for an allowed type and agreement between its real MIME type and extension, and an image library must be able to decode it. Reject HTML error pages, scripts, empty files, disguised files, and formats outside the approved list. Set pixel and memory thresholds for oversized images and decompression bombs, and use the site’s malware-scanning step when available.
A remote importer also needs its own business limit; wp_max_upload_size() reports the PHP upload ceiling, not a complete remote-fetch policy. Enforce the limit while streaming even if the response header claims a smaller size, and remove temporary files on failure.
5. Create understandable files and media metadata
Use WordPress filename sanitization and uniqueness handling. Do not expose path fragments, query parameters, secrets, or long random strings as public filenames. Use searchable media titles; preserve creator, source, and license requirements in the caption or description. Alt text should describe the image’s purpose in its current context; decorative images need empty alt text rather than keywords or a repeated filename.
Keep the original URL, source page, import time, rights basis, and—when useful—a content hash. _source_url helps with provenance but is not a license record. Crop, compress, or watermark only when the permission allows it, and never cover the creator’s identity with your own mark.
6. Review, replace, and retain a rollback path
Before publication, inspect thumbnails, body size, mobile rendering, alt text, captions, credits, duplicate attachments, and post links. Replace an image URL only after that attachment imported successfully and passed review. A failed item must not leave a half-converted post, and the importer should not automatically strip external source links from the article. Preserve per-batch lists of successes, skips, and failures; confirm the backup and rollback window before cleaning temporary files.
After publication, provide a correction or takedown route. If rights change, permission is withdrawn, or a source asset is replaced, the provenance record should locate every affected use for review.
Choose different paths for a few images and a migration
- A few manually edited images: After confirming permission, use the Image block’s “Insert from URL,” then “Upload to Media Library.” Inspect the resulting attachment, alt text, caption, and credit. This is easier to audit than installing an old plugin.
- A controlled migration: Choose a maintained importer from a trusted source that has passed security review, or have a developer build a constrained task around WordPress core media and safe HTTP APIs. Run a few manifest URLs on staging before proceeding in bounded batches.
- Unclear rights or boundaries: Do not fetch. Retain a link to the original page, request permission, or use your own or clearly licensed media.
This article intentionally provides no generic bulk-fetch code. Safety depends on host allowlists, DNS and redirect checks, download limits, content validation, authorization, logging, and rollback. A context-free snippet that merely “downloads” is not a production workflow.
Go / No-Go release checklist
| Check | Go | No-Go |
|---|---|---|
| Rights | Saved permission or license covers the intended use | Only “public online,” attribution alone, or an unreviewed fair-use assumption |
| Source | Page, file, rights holder, and license records are complete | Short link, mirror, anonymous file host, or access-control bypass |
| Network | HTTPS host allowlist; every redirect rechecked; private/metadata destinations rejected | Arbitrary URLs, internal exceptions, or disabled SSRF checks |
| Content | Real MIME, extension, and decode result agree | Trusting only a suffix/header, or accepting unexpected script/HTML/SVG content |
| Limits | Per-file, batch, pixel, time, and concurrency limits are enforced | Unbounded bulk run or reliance only on the PHP upload ceiling |
| Media record | Clear unique filename; contextual alt text; traceable credit, source, and license | Random filename, missing alt text, removed provenance, or unauthorized watermark |
| Operations | Small staging batch passed; database and files restore; logs and rollback exist | Full production run without a verified backup |
| Decision | Publish only when every required row is Go | Pause and fix any required No-Go item |
Current primary sources
- WordPress.org: `auto-save-image` plugin-directory status
- WordPress.org: Auto Save Remote Image, a separate legacy entry
- WordPress Image block: URL import, permission, and alt text
- WordPress Developer: `media_sideload_image()`
- WordPress Developer: `wp_safe_remote_request()` and SSRF protection
- WordPress Developer: `wp_check_filetype_and_ext()`
- WordPress Developer: `sanitize_file_name()`
- WordPress Developer: `wp_max_upload_size()`
- WordPress Advanced Administration Handbook: backing up the database and files
- U.S. Copyright Office: Photography & Copyright
These pages document current WordPress behavior and one U.S. copyright baseline; they are not legal advice for your jurisdiction. Seek qualified advice for material or disputed uses.
