External Media Importer
A WordPress plugin that scans your posts, pages, and custom post types for external media file URLs and imports them into your WordPress media library.
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/delphiknight/mediaflock/archive/refs/heads/main.zipGather all your scattered media into one flock. MediaFlock scans your WordPress posts, pages, and custom post types for external media file URLs, imports them into your media library, and replaces all references with local URLs — automatically.
Perfect for migrating sites away from external file hosts, consolidating CDN-hosted assets, or cleaning up content that still references third-party servers.
Features
- Batch scanning -- Scans posts in configurable batches (10--200 per request) to find external media URLs without overloading the server
- 5 URL extraction strategies -- Regex pattern matching, HTML tag parsing (
<img>,<video>,<audio>,<source>,<a>),srcsetattribute parsing, and CSSbackground-image: url(...)extraction - One-click import -- Downloads external files, creates WordPress media attachments, and replaces all URL variants in post content
- Smart URL replacement -- Handles HTML entity-encoded (
&), URL-encoded (%20), fully-encoded, and protocol-relative (//) URL variants - Post type and status filters -- Scan any public post type and filter by publish, draft, pending, private, or future status
- Quick Scan -- Scan a single post by entering its ID or URL
- Duplicate prevention -- Already-imported files are detected and shown with a badge, unchecked by default
- Dead link detection -- Files returning HTTP errors are marked as dead links and auto-skipped in future scans
- Resume interrupted scans -- Scan progress is saved to localStorage; a resume banner appears if a scan was interrupted
- Dry run mode -- Send HEAD requests to check file sizes before committing to an import
- Real-time progress -- Progress bar with file-by-file status updates during scanning and importing
- Import logs -- Paginated log page with status filter tabs (All / Success / Error / Skipped)
- CSV export -- Download filtered logs as a CSV file
- Retry failed imports -- One-click retry of all failed import entries
- Dashboard -- Stats overview showing total, success, error, and skipped counts with percentages, disk space used, and top error messages
- Configurable file types -- Select2 tagging interface for choosing allowed file extensions
- Multiple URL filters -- Select2 tagging interface for specifying external base URLs to limit scanning scope
- Configurable batch size -- Adjust the number of posts per AJAX request (10--200)
- Permission levels -- Restrict access to administrators only or open to editors and above
- Localization ready -- Full i18n support with English and Georgian translations included
- Clean uninstall -- Drops the log database table and deletes all plugin options on uninstall
Requirements
- WordPress 5.0 or higher
- PHP 7.2 or higher
Installation
- Download the plugin and upload the
mediaflockfolder to/wp-content/plugins/. - Activate the plugin through the Plugins menu in WordPress.
- Navigate to MediaFlock in the WordPress admin sidebar to begin scanning.
Alternatively, upload the plugin ZIP file via Plugins > Add New > Upload Plugin in the WordPress admin.
Usage
Scanning Posts
- Go to MediaFlock in the admin menu.
- Select a post type from the dropdown (posts, pages, or any registered custom post type).
- Check the post statuses you want to include (publish, draft, pending, private, future).
- Click Scan Posts.
- The plugin scans posts in batches, showing a progress bar. When finished, a table of posts with external media files is displayed.
Each result row shows the post title, the number of external files found, and checkboxes for each file. Files that have already been imported or are dead links are indicated with badges and are unchecked by default.
The plugin uses an SQL pre-filter to skip posts that cannot contain external file URLs, significantly improving scan speed on large sites.
Importing Files
- After scanning, review the list of found external files.
- Check or uncheck individual files as needed.
- Click Import Selected Files.
- A progress bar tracks the import. Each file is downloaded, added to the WordPress media library as an attachment, and the external URL in the post content is replaced with the new local URL.
The URL replacement logic handles multiple encoding variants of the same URL, ensuring no broken references remain in the content.
Quick Scan
- On the main MediaFlock page, find the Quick Scan section.
- Enter a post ID or a full post URL.
- Click Quick Scan.
- The plugin resolves the post and displays any external media files found, with the same import controls as a full scan.
This is useful for spot-checking individual posts without running a full scan.
Dry Run
- After scanning, select the files you want to check.
- Click Dry Run (Check Sizes).
- The plugin sends HTTP HEAD requests to each file URL and displays the file size next to each filename.
- A summary shows the total number of files and combined size.
Use this to estimate disk space requirements before importing.
Resume Scan
If a scan is interrupted (browser closed, network error, page navigation), the plugin saves progress to the browser's localStorage. When you return to the MediaFlock page:
- A resume banner appears showing the interrupted scan details.
- Click Resume to continue from where the scan left off.
- Click Dismiss to clear the saved state and start fresh.
Settings
Navigate to MediaFlock > Settings to configure the plugin.
File Types
Use the Select2 tagging field to specify which file extensions to scan for. Type an extension and press Enter to add it. Common types include jpg, png, gif, pdf, docx, mp4, and more.
External URL Filters
Use the Select2 tagging field to add one or more base URLs. When set, only files hosted on URLs starting with these base URLs will be included in scan results. This is useful for targeting a specific external server or CDN. Leave empty to scan for all external URLs.
Batch Size
Set the number of posts processed per AJAX request during scanning. The default is 50. Lower values (10--20) reduce server load; higher values (100--200) speed up scanning on capable servers. Range: 10--200.
Permission Level
Choose who can access the plugin:
- Administrators Only -- Only users with the
manage_optionscapability (default) - Editors and Above -- Users with the
edit_postscapability
Data Management
- Clear All Logs -- Deletes all entries from the import log table. A confirmation dialog is shown before clearing. The button is disabled when the log is empty.
Dashboard and Logs
Dashboard
Navigate to MediaFlock > Dashboard to view import statistics:
- Overview -- Total imports, success count, error count, and skipped count with percentages
- Storage -- Total disk space used by imported files and the number of unique posts affected
- Top Errors -- The 5 most frequent error messages to help diagnose import issues
Disk space data is cached for one hour using a WordPress transient.
Logs
Navigate to MediaFlock > Logs to view the import log:
- Logs are paginated at 50 entries per page.
- Use the status filter tabs (All / Success / Error / Skipped) to filter entries.
- Each log entry shows the post, file URL, status, and timestamp.
CSV Export
On the Logs page, click Export to CSV to download the current filtered log entries as a UTF-8 CSV file. The export respects the active status filter.
Retry Failed Imports
On the Logs page, click Retry Failed to re-attempt all imports that previously failed. The old error log entries are deleted before each retry. A progress bar tracks the retry process, and the page reloads when complete.
Translation
The plugin is fully internationalized. All user-facing strings in PHP use __() and _e(), and JavaScript strings are passed via wp_localize_script().
Included Languages
- English (default)
- Georgian (
ka_GE)
Adding a New Translation
- Use a tool like Poedit or Loco Translate to open the
.potfile located in thelanguages/directory. - Translate the strings into your language.
- Save the
.poand.mofiles with the correct locale code (e.g.,mediaflock-fr_FR.poandmediaflock-fr_FR.mo). - Place the files in the
languages/directory inside the plugin folder.
Screenshots
- Main scan page -- Post type selector, status filters, and scan button
- Scan results -- Table of posts with external files, checkboxes, and import controls
- Import progress -- Real-time progress bar during file import
- Quick Scan -- Single post scan by ID or URL
- Dry run results -- File size badges displayed next to each file
- Settings page -- File types, URL filters, batch size, and permission configuration
- Dashboard -- Stats overview with counts, percentages, and disk space
- Logs page -- Paginated log with status filter tabs and export button
Changelog
1.0.32
- Added
wp_unslash()before all sanitization on$_GET/$_POSTsuperglobals - Wrapped
wp_verify_nonce()input withsanitize_text_field(wp_unslash()) - Escaped
get_edit_post_link()output withesc_url() - Replaced manual
selected/disabledattributes with WordPressselected()anddisabled()functions - Escaped
paginate_links()output withwp_kses_post()
1.0.31
- Renamed plugin to MediaFlock with new slug
mediaflockand text domainmediaflock - Updated all prefixes from
emi_tomflk_(4-character minimum per WordPress guidelines) - Updated all CSS classes, HTML IDs, AJAX actions, nonces, options, and localStorage keys
1.0.30
- WordPress.org review compliance: all output escaped with
esc_html_e(),esc_html__(),wp_kses(),esc_js() - Bundled Select2 library locally (removed CDN dependency)
- Moved inline styles to external CSS file
1.0.29
- Full localization: wrapped all PHP strings in translation functions, passed JS strings via
mflkAjax.i18n, addedload_plugin_textdomain()support, created.pottemplate and Georgian (ka_GE) translation files - Added English README.md and Georgian README-ka.md documentation
1.0.28
- Added Strategy 4:
srcsetattribute parsing on<img>and<source>tags for responsive image URLs - Added Strategy 5: CSS
background-image: url(...)extraction from inline styles and `