Cómo eliminar correctamente entradas con metadatos y archivos adjuntos

17 feb 2014, 13:22:27
Vistas: 19K
Votos: 10

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&amp;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?

2
Comentarios

Hasta donde yo sé, no hay una forma "integrada" de hacer esto, necesitarías construir tu propia manera de hacerlo. No estoy seguro de cuál es tu nivel de codificación en PHP/WP, pero esencialmente tendrías que ejecutar una consulta para encontrar todos los archivos adjuntos del Post, otra para eliminarlos, otra para encontrar el meta del Post y otra más para eliminarlos. Creo que cuando elimines el Post, WordPress se encargará de actualizar todas las tablas de Taxonomía por ti, así que no debería ser necesaria ninguna acción allí.

David Gard David Gard
17 feb 2014 16:27:13

El meta del Post debería eliminarse cuando el post se borra (pero no cuando se "envía a la papelera"). Los archivos adjuntos quedarán huérfanos pero no se eliminarán. Tendrás que encargarte de esa parte tú mismo.

s_ha_dum s_ha_dum
17 feb 2014 16:30:23
Todas las respuestas a la pregunta 2
5
10

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' );
17 feb 2014 16:58:29
Comentarios

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.

David Gard David Gard
17 feb 2014 17:11:34

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.

Howdy_McGee Howdy_McGee
17 feb 2014 17:19:29

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).

David Gard David Gard
17 feb 2014 17:27:51

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

Howdy_McGee Howdy_McGee
17 feb 2014 17:37:18

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.

David Gard David Gard
17 feb 2014 17:46:24
3

@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.

17 feb 2014 16:51:47
Comentarios

¿Cómo puedo verificar el tipo de publicación?

4ndro1d 4ndro1d
17 feb 2014 16:58:00

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í.

David Gard David Gard
17 feb 2014 17:13:10

Esto también necesita una consulta para $wpdb->postmeta de lo contrario habrá valores huérfanos en la tabla postmeta que nunca serán eliminados.

Howdy_McGee Howdy_McGee
9 jun 2016 01:45:25