Cómo eliminar correctamente entradas con metadatos y archivos adjuntos
Estoy revisando tipos de entradas personalizadas. Estas tienen taxonomías personalizadas y también un archivo adjunto.
En mi vista general necesito proporcionar enlaces para eliminar las entradas. Con eso también necesito eliminar el adjunto y los metadatos.
Estaba usando esto:
if ( !current_user_can( 'delete_bkroadkill', $post->ID ) )
return;
$link = "<a href='" . wp_nonce_url( get_bloginfo('url') . "/wp-admin/post.php?action=delete&post=" . $post->ID, 'delete-post_' . $post->ID) . "'>".$link."</a>";
echo $before . $link . $after;
Encontré Enlace para eliminar post, sus metadatos y adjuntos pero no hay una solución proporcionada.
Esto no eliminará nada más que la entrada. ¿Cuál es la forma correcta de hacer esto?
Yo uso esto para eliminar los archivos multimedia asociados a un post. Si quieres probarlo con un tipo de post específico puedes incluir la variable global $post_type
. Básicamente obtiene todos los adjuntos y los elimina uno por uno. Referencia
function delete_associated_media( $id ) {
$media = get_children( array(
'post_parent' => $id,
'post_type' => 'attachment'
) );
if( empty( $media ) ) {
return;
}
foreach( $media as $file ) {
wp_delete_attachment( $file->ID );
}
}
add_action( 'before_delete_post', 'delete_associated_media' );

Si bien eso funciona, sugiero crear un array de IDs para eliminar, luego construir una consulta personalizada y ejecutarla. Tu respuesta ejecutará múltiples consultas para eliminar los adjuntos; quizás no sea un problema para 3 o 4, pero si tienes 100 adjuntos podría ralentizar las cosas considerablemente.

Este código no ejecuta más consultas que el tuyo. Consulta una vez para obtener los adjuntos, luego 1 consulta para eliminarlos, todo a través de WordPress en lugar de cualquier SQL personalizado.

Incorrecto. Estás consultando la base de datos una vez para obtener todos los adjuntos y luego una vez por adjunto cuando los eliminas; 10 adjuntos = 11 consultas en total. Yo consulto una vez para obtener todos los adjuntos y una vez para eliminar todas las publicaciones asociadas; 10 adjuntos = 2 consultas. Sin embargo, cabe señalar que tu código también elimina el archivo, mientras que el mío simplemente elimina la fila ofensiva de la base de datos. Supongo que es una preferencia personal, pero por rendimiento lo haría a mi manera y luego ejecutaría alguna tarea de mantenimiento para eliminar adjuntos no asociados (un complemento simple podría manejar eso).

Entiendo lo que dices. Pensé que el objetivo era eliminar los archivos adjuntos por completo cuando se borra una publicación.

El OP (publicador original) puede haber querido decir eso, supongo que depende de cómo lo interpretes. Por experiencia previa, he encontrado que mantener las tareas de mantenimiento potencialmente lentas lejos de los usuarios contribuye a una mejor experiencia, por eso lo interpreté de esa manera.

@s_ha_dum sugiere que los metadatos de las publicaciones se eliminarán automáticamente. Por lo tanto, dado que su reputación sugiere que sabe de lo que está hablando, esta solución solo maneja los archivos adjuntos de las publicaciones.
Sugeriría revisar la documentación del hook before_delete_post(), ya que es bastante útil poder verificar qué tipo de publicación se está eliminando, etc.
add_action('before_delete_post', 'delete_post_attachments');
function delete_post_attachments($post_id){
global $post_type;
if($post_type !== 'my_custom_post_type') return;
global $wpdb;
$args = array(
'post_type' => 'attachment',
'post_status' => 'any',
'posts_per_page' => -1,
'post_parent' => $post_id
);
$attachments = new WP_Query($args);
$attachment_ids = array();
if($attachments->have_posts()) : while($attachments->have_posts()) : $attachments->the_post();
$attachment_ids[] = get_the_id();
endwhile;
endif;
wp_reset_postdata();
if(!empty($attachment_ids)) :
$delete_attachments_query = $wpdb->prepare('DELETE FROM %1$s WHERE %1$s.ID IN (%2$s)', $wpdb->posts, join(',', $attachment_ids));
$wpdb->query($delete_attachments_query);
endif;
}
Una nota importante de la documentación mencionada anteriormente -
Es importante destacar que el hook se ejecuta solo cuando el usuario de WordPress vacía la papelera. Si usas este hook, ten en cuenta que no se activará si el usuario está eliminando un archivo adjunto, ya que los archivos adjuntos se eliminan de forma permanente, es decir, no se envían a la papelera. En su lugar, usa el hook delete_post().
Otra nota
Debería mencionar que, aunque el código en esta respuesta eliminará todas las filas de la base de datos relacionadas con los archivos adjuntos de la publicación, en realidad no eliminará los archivos adjuntos en sí.
Mi razonamiento para esto es el rendimiento. Dependiendo del número de archivos adjuntos que tengas, eliminarlos uno por uno podría llevar un tiempo. Sugiero que es mejor eliminar solo las entradas de la base de datos para todos los archivos adjuntos inicialmente para mejorar la experiencia del usuario, y luego ejecutar alguna limpieza por separado en otro momento para eliminar los archivos adjuntos reales (es bastante fácil buscar y eliminar archivos no asociados). Básicamente, menos consultas + menos trabajo durante la experiencia del usuario = menos tiempo.

He actualizado mi respuesta (obviamente reemplaza my_custom_post_type
con el tipo de publicación relevante). También, revisa el enlace en la publicación para el hook before_delete_post(), está completamente explicado allí.
