Añadir imagen a la biblioteca multimedia desde URL en directorio de subidas
El plugin "Video Embed & Thumbnail Generator" hace un excelente trabajo generando miniaturas a partir de videos. Guarda la URL de la miniatura como metadato para el adjunto. La miniatura se añade al directorio de subidas. ¿Hay alguna forma de tomar esta imagen y añadirla a la biblioteca multimedia para poder pasar la imagen por la función image_downsize y crear una miniatura de un tamaño diferente?
wp_insert_attachment parece que necesita una ruta a un archivo y no una URL, ¿o estoy equivocado? ¿Cómo puedo añadir una URL a la biblioteca multimedia?
Esto posiblemente sea un duplicado de ¿Cómo puedo obtener una imagen del directorio de subidas y agregarla a la biblioteca multimedia? pero esa pregunta nunca obtuvo respuestas.

Si la imagen está en el contenido fuente puedes extraerla y usar media_sideload_image(); para importarla a la biblioteca de medios.
Este código de ejemplo es de mi plugin Media Tools. Que realiza esta acción a través de una página de administración vía AJAX. También establece la imagen extraída como imagen destacada para la entrada. El ID de la entrada se pasa a esta función mediante AJAX. Para ver el código completo consulta: http://plugins.trac.wordpress.org/browser/media-tools/trunk/media-tools.php?rev=581988
function process_image( $post_id ) {
$response = '';
$error = 0;
$post = get_post( $post_id );
$img = $this->extract_image( $post );
if( empty( $img ) ) {
$response .= 'No se encontraron imágenes <br>';
die( sprintf( $response . '<br>Herramienta de medios completada (ID de entrada %1$s) en %2$s segundos. %3$d errores', esc_html( $post->ID ), timer_stop(), $error = $error > 0 ? $error : 'ninguno' ) );
}
/** @var $file string o WP_Error de la imagen adjunta a la entrada */
$file = media_sideload_image( $img, (int)$post->ID );
if ( is_wp_error( $file ) ) {
$response .= '<span style="color:red">Error de carga: No se pudo subir la imagen. Verifica si hay URL src malformada en la imagen</span><br>';
$error++;
} else {
$atts = $this->get_attach( $post->ID );
foreach ( $atts as $a ) {
$img = set_post_thumbnail( $post->ID, $a['ID'] );
if ( $img ) {
$thumb = wp_get_attachment_thumb_url( $a['ID'] );
$response .= '<img src="'.esc_url( $thumb ).'" /><br>';
$response .= '<a href="'.wp_nonce_url( get_edit_post_link( $a['ID'], true ) ).'" >'.get_the_title( $a['ID'] ).'</a> Establecida como Imagen Destacada</p><br>';
}
}
unset( $atts );
unset( $a );
}
die( sprintf( $response.'<br>Herramienta de medios completada (ID de entrada %1$s) en %2$s segundos. %3$d errores', esc_html( $post->ID ), timer_stop(), $error = $error > 0 ? $error : 'ninguno' ) );
}
/**
* Extrae la primera imagen en el contenido de la entrada
* @param object $post el objeto de la entrada
* @return bool|string false si no hay imágenes o src de la imagen
*/
function extract_image( $post ) {
$html = $post->post_content;
if ( stripos( $html, '<img' ) !== false ) {
$regex = '#<\s*img [^\>]*src\s*=\s*(["\'])(.*?)\1#im';
preg_match( $regex, $html, $matches );
unset( $regex );
unset( $html );
if ( is_array( $matches ) && ! empty( $matches ) ) {
return $matches[2];
} else {
return false;
}
} else {
return false;
}
}
/**
* Consulta las imágenes adjuntas
* @param int $post_id El ID de la entrada para verificar si existen adjuntos
* @return array|bool El primer adjunto en éxito, false si no hay adjuntos
*/
function get_attach( $post_id ) {
return get_children( array (
'post_parent' => $post_id,
'post_type' => 'attachment',
'post_mime_type' => 'image',
'posts_per_page' => (int)1
), ARRAY_A );
}

media_sideload_image() parece prometedor, pero ¿cómo se obtiene el ID del adjunto para la imagen cargada de forma externa?

Mira la función get_attach. Se ejecuta después de media_sideload_image.

¿te refieres a get_attachment? eso necesita el ID que aún no tengo. Voy a echar un vistazo a media_handle_sideload()

además, la carga lateral de medios no es del todo correcta porque duplica imágenes que ya están en la carpeta wp-uploads (donde el plugin de video embedder las está agregando)

Bueno, el video embedder debería agregarlas a tu biblioteca de medios en lugar de simplemente volcarlas en tu directorio de uploads.

Aquí están las partes relevantes que cambié de la función kg_video_attachment_fields_to_save()
que filtra attachment_fields_to_save
:
$thumb_url = $attachment['kgflashmediaplayer-poster'];
//inserta la $thumb_url en la biblioteca de medios si no existe ya
if ( ! ($thumb_id = get_attachment_id_from_src( $thumb_url ) ) ) {
$post_id = $post['ID'];
$desc = $attachment['post_title'] . ' miniatura';
//¿está la imagen en el directorio de uploads?
$upload_dir = wp_upload_dir();
if ( FALSE !== strpos( $url, $upload_dir['baseurl'] ) ) {
$wp_filetype = wp_check_filetype(basename($thumb_url), null );
$filename = preg_replace('/\.[^.]+$/', '', basename($thumb_url));
$attachment = array(
'guid' => $thumb_url,
'post_mime_type' => $wp_filetype['type'],
'post_title' => $desc,
'post_content' => '',
'post_status' => 'inherit'
);
$thumb_id = wp_insert_attachment( $attachment, basename($thumb_url), $post_id );
// primero debes incluir el archivo image.php
// para que la función wp_generate_attachment_metadata() funcione
require_once(ABSPATH . 'wp-admin/includes/image.php');
$attach_data = wp_generate_attachment_metadata( $thumb_id, basename($thumb_url) );
wp_update_attachment_metadata( $thumb_id, $attach_data );
} else { //no está en uploads así que tendremos que sideloadearlo
$tmp = download_url( $thumb_url );
// Establece variables para almacenamiento
// corrige el nombre del archivo para query strings
preg_match('/[^\?]+\.(jpg|JPG|jpe|JPE|jpeg|JPEG|gif|GIF|png|PNG)/', $thumb_url, $matches);
$file_array['name'] = basename($matches[0]);
$file_array['tmp_name'] = $tmp;
// Si hay error almacenando temporalmente, elimina
if ( is_wp_error( $tmp ) ) {
@unlink($file_array['tmp_name']);
$file_array['tmp_name'] = '';
}
// hace la validación y almacenamiento
$thumb_id = media_handle_sideload( $file_array, $post_id, $desc );
// Si hay error almacenando permanentemente, elimina
if ( is_wp_error($thumb_id) ) {
@unlink($file_array['tmp_name']);
return $thumb_id;
}
if ( $local_src = wp_get_attachment_url( $thumb_id ) ) {
update_post_meta($post['ID'], '_kgflashmediaplayer-poster', $local_src);
}
} //fin sideload
} //fin get_attachment_id_from_src
if(!is_wp_error($thumb_id)) {
$thumb_id = intval( $thumb_id );
update_post_meta($post['ID'], '_kgflashmediaplayer-poster-id', $thumb_id);
}
Y el ID de la miniatura personalizada del video ahora se almacena en el campo meta: _kgflashmediaplayer-poster-id
function get_attachment_id_from_src ($image_src) {
global $wpdb;
$query = "SELECT ID FROM {$wpdb->posts} WHERE guid='$image_src'";
$id = $wpdb->get_var($query);
return $id;
}
No me encanta la función get_attachment_id_from_src()
pero no hay una forma integrada de hacer esto. Debería agregar una verificación para que si la src actual es la misma que la anterior, esta consulta no necesite ejecutarse. El plugin de inserción crea muchas miniaturas potenciales para cada video y no hay necesidad de insertarlas todas en la biblioteca de medios... así que esto se ejecuta cada vez que se guarda un archivo adjunto de medios y debería cubrir imágenes que ya están en la biblioteca de medios, imágenes que están en el directorio de medios pero no en la biblioteca e imágenes en otros servidores (que se cargan de forma remota y la URL se ajusta a la nueva URL local)

Función maravillosa... necesitó un poco de ajustes pero funcionó genial para mis necesidades ;)

Como esto tiene 3 años, asumo que ahora hay una forma mucho mejor de hacerlo.

aún funcionó para mí - que es todo lo que necesitaba ;) - un código detallado, rápido y listo para usar. gracias.
