Skip to content

Instantly share code, notes, and snippets.

@cloudinstone
Last active February 16, 2025 09:06
Show Gist options
  • Save cloudinstone/0455db897245763f597c1de99f27037b to your computer and use it in GitHub Desktop.
Save cloudinstone/0455db897245763f597c1de99f27037b to your computer and use it in GitHub Desktop.
ExternalImageHelper.php
<?php
namespace SC\IT205\ExternalImages;
use WP_Error;
use WP_Query;
if (!function_exists('download_url')) {
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
}
class ExternalImageHelper {
public static function media_sideload_image($file, $post_id = 0, $desc = null, $return = 'html') {
if (!empty($file)) {
$file_array = array();
// Download file to temp location.
$file_array['tmp_name'] = download_url($file);
// If error storing temporarily, return the error.
if (is_wp_error($file_array['tmp_name'])) {
return $file_array['tmp_name'];
}
$allowed_extensions = array('jpg', 'jpeg', 'jpe', 'png', 'gif', 'webp');
/**
* Filters the list of allowed file extensions when sideloading an image from a URL.
*
* The default allowed extensions are:
*
* - `jpg`
* - `jpeg`
* - `jpe`
* - `png`
* - `gif`
*
* @since 5.6.0
*
* @param string[] $allowed_extensions Array of allowed file extensions.
* @param string $file The URL of the image to download.
*/
$allowed_extensions = apply_filters('image_sideload_extensions', $allowed_extensions, $file);
$allowed_extensions = array_map('preg_quote', $allowed_extensions);
// Set variables for storage, fix file filename for query strings.
preg_match('/[^\?]+\.(' . implode('|', $allowed_extensions) . ')\b/i', $file, $matches);
if ($matches) {
$ext = $matches[1];
$file_array['name'] = wp_basename($matches[0]);
} else {
$pathinfo = pathinfo($file);
$filename_without_ext = $pathinfo['filename'];
$file_mime_type = mime_content_type($file_array['tmp_name']);
$ext = str_replace('image/', '', $file_mime_type);
$file_array['name'] = $filename_without_ext . '.' . $ext;
}
if (!in_array($ext, $allowed_extensions)) {
@unlink($file_array['tmp_name']);
return new WP_Error('image_sideload_failed', __('Invalid image URL.'));
}
// Do the validation and storage stuff.
$id = media_handle_sideload($file_array, $post_id, $desc);
// If error storing permanently, unlink.
if (is_wp_error($id)) {
@unlink($file_array['tmp_name']);
return $id;
}
// Store the original attachment source in meta.
add_post_meta($id, '_source_url', $file);
// If attachment ID was requested, return it.
if ('id' === $return) {
return $id;
}
$src = wp_get_attachment_url($id);
}
// Finally, check to make sure the file has been saved, then return the HTML.
if (!empty($src)) {
if ('src' === $return) {
return $src;
}
$alt = isset($desc) ? esc_attr($desc) : '';
$html = "<img src='$src' alt='$alt' />";
return $html;
} else {
return new WP_Error('image_sideload_failed');
}
}
public static function external_image_attachment_exists($url, $check_meta = true) {
global $wpdb;
$attachment_id = $wpdb->get_var($wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE guid=%s", $url));
if ($check_meta && !$attachment_id) {
$query = new WP_Query(
array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'fields' => 'ids',
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'meta_query' => array(
array(
'key' => '_source_url',
'value' => $url,
),
),
)
);
$attachment_id = !empty($query->posts) ? $query->posts[0] : 0;
}
return (int) $attachment_id;
}
/**
* Insert an exteranl image attachment.
*
* @param string $url
* @param array $args
* @return int|WP_Error The attachment ID on success. The value 0 or WP_Error on failure.
*/
public static function insert_external_image_attachment($url = '', $args = array(), $save_file = false) {
$args = wp_parse_args(
$args,
array(
'post_parent' => 0,
'required_info' => true,
)
);
if ($save_file) {
return self::media_sideload_image($url, $args['post_parent'], null, 'id');
}
$filename = wp_basename($url);
// Download image to a local temporary file
$file = download_url($url);
if (is_wp_error($file) && $args['required_info']) {
return $file;
}
// Get image info.
$info = wp_getimagesize($file);
if (!$info && $args['required_info']) {
@unlink($file);
return new WP_Error('no_size', __('Could not get image size.', ''));
}
$title = preg_replace('/\.[^.]+$/', '', $filename);
$content = '';
// Use image exif/iptc data for title and caption defaults if possible.
$image_meta = wp_read_image_metadata($file);
if ($image_meta) {
if (trim($image_meta['title']) && !is_numeric(sanitize_title($image_meta['title']))) {
$title = $image_meta['title'];
}
if (trim($image_meta['caption'])) {
$content = $image_meta['caption'];
}
}
// Insert attachment.
$data = array(
'guid' => $url,
'post_mime_type' => $info['mime'],
'post_title' => $title,
'post_content' => $content,
'post_parent' => $args['post_parent'],
);
$attachment_id = wp_insert_attachment($data);
// Update metadata.
$metadata = array(
'width' => $info[0],
'height' => $info[1],
'file' => preg_replace('/\?[^?]+$/', '', $filename),
);
/**
* It's neccessary to make sure that WP built-in attachment related
* functions to working. e.g. `wp_get_attachemnt_image`.
*/
$metadata['file'] = $filename;
$metadata['sizes'] = array('full' => $metadata);
wp_update_attachment_metadata($attachment_id, $metadata);
@unlink($file);
return $attachment_id;
}
public static function is_external($url) {
$local_domain = parse_url(get_bloginfo('url'))['host'];
$domain = parse_url($url)['host'];
return $local_domain == $domain;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment