Verificar si un archivo ya existe en la Biblioteca Multimedia
Estoy creando archivos personalizados en un plugin y agregándolos a la Biblioteca Multimedia usando el código proporcionado en el Codex de WordPress para wp_insert_attachment. Sin embargo, mi plugin a veces sobrescribe esos archivos. Necesito asegurarme de que los archivos no se agreguen nuevamente a la Biblioteca Multimedia. Aquí está el código actual:
$wp_filetype = wp_check_filetype(basename($filename), null );
$wp_upload_dir = wp_upload_dir();
$attachment = array(
'guid' => $wp_upload_dir['baseurl'] . '/' . _wp_relative_upload_path( $filename ),
'post_mime_type' => $wp_filetype['type'],
'post_title' => preg_replace('/\.[^.]+$/', '', basename($filename)),
'post_content' => '',
'post_status' => 'inherit'
);
$attach_id = wp_insert_attachment( $attachment, $filename);
// 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( $attach_id, $filename );
wp_update_attachment_metadata( $attach_id, $attach_data );
Solo necesito verificar si el archivo ya es parte de la Biblioteca Multimedia, y actualizarlo si es así. No tengo un post_id con el que trabajar, solo el permalink y el guid.
Gracias por tu ayuda.

global $wpdb;
$image_src = wp_upload_dir()['baseurl'] . '/' . _wp_relative_upload_path( $filename );
$query = "SELECT COUNT(*) FROM {$wpdb->posts} WHERE guid='$image_src'";
$count = intval($wpdb->get_var($query));
Puedes usar esto al inicio de tu código. Luego verifica el valor de $count
. Si es 0, entonces puedes continuar agregando el adjunto

Tengo este método (gracias Mridul):
function MediaFileAlreadyExists($filename){
global $wpdb;
$query = "SELECT COUNT(*) FROM {$wpdb->postmeta} WHERE meta_value LIKE '%/$filename'";
return ($wpdb->get_var($query) > 0) ;
}
// MediaFileAlreadyExists("my-image.png");

Sé que esta es una pregunta antigua, pero no me gustó ninguna de las respuestas existentes, así que aquí está mi solución.
Esto verificará si el archivo existe. Si es así, actualizará el adjunto existente; si no, creará un nuevo adjunto.
// Obtener directorio de subida
$upload_dir = wp_upload_dir();
$upload_folder = $upload_dir['path'];
// Establecer nombre de archivo, incluyendo ruta
$filename = "{$upload_folder}/miarchivo-{$id}.pdf";
// Verificar el tipo de archivo. Lo usaremos como 'post_mime_type'.
$filetype = wp_check_filetype( basename( $filename ), null );
// Obtener título del archivo
$title = preg_replace( '/\.[^.]+$/', '', basename( $filename ) );
// Preparar array de datos para el adjunto
$attachment_data = array(
'guid' => $upload_dir['url'] . '/' . basename( $filename ),
'post_mime_type' => $filetype['type'],
'post_title' => $title,
'post_content' => '',
'post_status' => 'inherit'
);
// ¿Existe ya el adjunto?
if( post_exists( $title ) ){
$attachment = get_page_by_title( $title, OBJECT, 'attachment');
if( !empty( $attachment ) ){
$attachment_data['ID'] = $attachment->ID;
}
}
// Si no hay ID padre establecido, restablecer a valor por defecto (0)
if( empty( $parent_id ) ){
$parent_id = 0;
}
// Insertar el adjunto
$attach_id = wp_insert_attachment( $attachment_data, $filename, $parent_id );
// Generar los metadatos para el adjunto y actualizar el registro en la base de datos
$attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
wp_update_attachment_metadata( $attach_id, $attach_data );
En el ejemplo anterior estoy usando un .pdf en mi variable $filename pero puedes reemplazarlo con cualquier nombre de archivo/tipo de archivo.

Puedes verificar si una imagen existe con post_exists($filename)
. Si la imagen existe puedes actualizarla, de lo contrario puedes crearla
// Si la imagen existe, actualizarla, de lo contrario crearla
if (post_exists($filename)){
$page = get_page_by_title($filename, OBJECT, 'attachment');
$attach_id = $page->ID;
$attach_data = wp_generate_attachment_metadata( $attach_id, $destination ); // Generar metadatos del adjunto: tamaño de archivo, altura, anchura, etc.
wp_update_attachment_metadata( $attach_id, $attach_data ); // Añadir los metadatos anteriores
add_post_meta($attach_id, '_wp_attachment_image_alt', $filealt); // Añadir el texto alternativo
}
else{
$attach_id = wp_insert_attachment( $attachment, $destination, $post_id );
$attach_data = wp_generate_attachment_metadata( $attach_id, $destination );
wp_update_attachment_metadata( $attach_id, $attach_data );
add_post_meta($attach_id, '_wp_attachment_image_alt', $filealt);
}

¿Podrías agregar una explicación en la respuesta sobre cómo funciona el código?

post_exists automáticamente devuelve el ID del post si el post existe, así que no hay razón para usar get_page_by_title()
https://developer.wordpress.org/reference/functions/post_exists/

Esta función toma como parámetro el nombre del archivo multimedia y devuelve el meta_id si existe, de lo contrario devuelve (false).
function MediaFileAlreadyExists($filename){
global $wpdb;
$query = "SELECT meta_id FROM {$wpdb->postmeta} WHERE meta_value LIKE '%/$filename'";
if ( $wpdb->get_var($query) ){
return $wpdb->get_var($query);
}
return false;
}

Me gusta el uso del LIKE. Cuando WordPress sube un duplicado, añade un -x al nombre del archivo. Algunos plugins anteponen una clave única para evitar duplicados (Media Cloud). post_exists($filename) no detectará esto. Modificaré el tuyo para manejar tanto el prefijo como el sufijo de $basename. Gracias.
