Files

  • lh-add-media-from-url.php — main plugin file. Singleton LH_add_media_from_url_plugin, hooked via plugins_loaded. Registers the Media -> Add from URL admin page and handles the upload form submission on admin_init. Thin controller only — no HTML lives in this class.
  • includes/lh-add-media-from-url-copy-from-url.php — LH_add_media_from_url_copy_from_url, a composed helper class (not a PHP subclass of the main plugin) that does the actual remote fetch and sideload into the media library.
  • includes/lh-add-media-from-url-abilities.php — LH_add_media_from_url_abilities, registers the plugin’s MCP ability. Loaded from plugins_init() only on the main site and only if the Abilities API is present.
  • partials/admin-page.php — the admin page’s own markup: header, any upload error, the upload form include, and the bookmarklet block.
  • partials/upload.php — the upload form markup itself, included from admin-page.php.

Key methods

  • LH_add_media_from_url_copy_from_url::save_external_file( $url, $post_id, $desc, $check ) — downloads $url to a temp file via wp_safe_remote_get(), validates it, guesses its extension with wp_check_filetype_and_ext(), and sideloads it via media_handle_sideload(). Stores the original URL as post meta _lh_copy_from_url-original_file.
  • guess_file_extension() inspects the already-downloaded local temp file rather than re-fetching the remote URL, so extension/MIME detection stays inside WP core’s own SSRF-protected fetch path.

MCP ability

  • lh-add-media-from-url/add-media-from-url — wraps save_external_file() so an MCP agent can pull a remote file into the media library the same way the manual wp-admin form does. Accepts url (required), post_id, desc. Returns the new attachment id and url.
  • Gated to upload_files, matching the manual form’s own capability check in handle_upload_v2() — deliberately not the edit_posts pattern used by content-operation abilities like lh-portfolio’s, since a Contributor with edit_posts but not upload_files should not gain upload access through this ability that the wp-admin screen would refuse them.

Hooks

  • Filter lh_add_media_from_url_remote_get_args — filters the args array passed to wp_safe_remote_get() when fetching the remote file.
  • Filter lh_add_media_from_url_init_plugin — return false to prevent the plugin’s admin_menu/admin_init hooks and the MCP ability from registering.

Capability

Gated to upload_files rather than the LH-standard install_plugins default — deliberate, since this is a media-upload tool for any user who can already upload files, not developer/admin tooling.

Database / cron

No custom database tables. No cron jobs. The only persistent data is the _lh_copy_from_url-original_file post meta on each created attachment.

Notes

  • The bookmarklet’s $_GET read in plugin_options() is a read-only display convenience (pre-filling the URL field), not a state-changing action — it can’t carry a nonce, since a bookmarklet is a static link with no server round-trip to mint one. The actual state-changing step, handle_upload_v2(), does verify a nonce before anything is fetched or written.