Eliminare correttamente post con meta e allegati

17 feb 2014, 13:22:27
Visualizzazioni: 19K
Voti: 10

Sto gestendo una panoramica di custom post types. Questi hanno tassonomie personalizzate e anche un allegato.

Nella mia panoramica devo fornire link per eliminare le voci. Con questo devo anche eliminare l'allegato e i metadati.

Stavo usando questo codice:

    // Verifica i permessi dell'utente
    if ( !current_user_can( 'delete_bkroadkill', $post->ID ) )
        return;

    // Crea il link per l'eliminazione
    $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;

Ho trovato Delete Post Link to delete post, its meta and attachments ma non viene fornita alcuna soluzione.

Questo codice elimina solo il post, nient'altro. Qual è il modo corretto per farlo?

2
Commenti

Per quanto ne so, non esiste un modo "integrato" per fare questo, dovresti creare un metodo per farlo da solo. Non sono sicuro del tuo livello di codifica PHP/WP, ma fondamentalmente dovresti eseguire una query per trovare tutti gli allegati del Post, un'altra per eliminarli, un'altra ancora per trovare i meta del Post e un'ultima per eliminarli. Credo che quando poi elimini il Post, WP gestisca l'aggiornamento di tutte le tabelle delle Tassonomie per te, quindi non dovrebbe essere necessaria alcuna azione lì.

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

I meta del Post dovrebbero essere eliminati quando il post viene cancellato (ma non quando viene "spostato nel cestino"). Gli allegati rimarranno orfani ma non verranno eliminati. Dovrai occuparti tu di quella parte.

s_ha_dum s_ha_dum
17 feb 2014 16:30:23
Tutte le risposte alla domanda 2
5
10

Utilizzo questa funzione per eliminare i media associati a un articolo. Se vuoi testarla su un determinato tipo di articolo puoi includere la variabile global $post_type. In sostanza, ottiene tutti gli allegati e li elimina uno per uno. Riferimento

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
Commenti

Anche se funziona, suggerirei di creare un array di ID da eliminare, poi costruire una query personalizzata ed eseguirla. La tua risposta eseguirà più query per eliminare gli allegati; forse non è un problema per 3 o 4, ma se hai 100 allegati potrebbe rallentare notevolmente le operazioni.

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

Questo codice non esegue più query del tuo. Esegue una query per ottenere gli allegati, poi 1 query per eliminarli, tutto tramite WordPress invece di usare SQL personalizzato.

Howdy_McGee Howdy_McGee
17 feb 2014 17:19:29

Non corretto. Tu esegui una query al database per ottenere tutti gli allegati e poi una query per allegato quando li elimini; 10 allegati = 11 query in totale. Io eseguo una query per ottenere tutti gli allegati e una per eliminare tutti i post associati; 10 allegati = 2 query. Va notato però che il tuo codice elimina anche il file, mentre il mio si limita a rimuovere la riga incriminata dal database. Immagino sia una questione di preferenze personali, ma per le prestazioni lo farei a modo mio e poi eseguirei qualche operazione di pulizia per rimuovere gli allegati non associati (un semplice plugin potrebbe gestirlo).

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

Capisco cosa intendi. Pensavo che l'obiettivo fosse rimuovere completamente gli allegati quando un articolo veniva eliminato.

Howdy_McGee Howdy_McGee
17 feb 2014 17:37:18

L'autore del post potrebbe aver inteso quello, suppongo dipenda dall'interpretazione. Dalla mia esperienza precedente ho notato che tenere lontane dagli utenti le attività di manutenzione potenzialmente dispendiose in termini di tempo contribuisce a una migliore esperienza, quindi l'ho interpretato in quel modo.

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

@s_ha_dum suggerisce che i meta dei post verranno eliminati automaticamente. Pertanto, dato che la sua reputazione indica che sa di cosa parla, questa soluzione gestisce solo gli allegati dei post.

Suggerirei di consultare la documentazione per l'hook before_delete_post(), poiché è molto utile poter verificare quale tipo di post viene eliminato, ecc.

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;

}

Un'importante nota dalla documentazione citata -

È importante notare che l'hook viene eseguito solo quando l'utente di WordPress svuota il Cestino. Se usi questo hook tieni presente che non verrà attivato se l'utente sta eliminando un Allegato, poiché gli allegati vengono eliminati definitivamente, cioè non inviati al Cestino. Invece usa l'hook delete_post().

Un'altra nota

Dovrei menzionare che mentre il codice in questa risposta eliminerà tutte le righe dal database relative agli allegati del post, in realtà non eliminerà gli allegati stessi.

La mia motivazione per questo è la performance. A seconda del numero di allegati che hai, eliminarli uno alla volta potrebbe richiedere del tempo. Suggerisco che è meglio eliminare inizialmente solo le voci del database per tutti gli allegati per migliorare l'esperienza utente, e poi eseguire una pulizia separata in un altro momento per eliminare gli allegati effettivi (è abbastanza facile cercare ed eliminare i file non associati). In sostanza, meno query + meno lavoro durante l'esperienza utente = meno tempo.

17 feb 2014 16:51:47
Commenti

Come posso verificare il tipo di post?

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

Ho aggiornato la mia risposta (ovviamente sostituisci my_custom_post_type con il tipo di post rilevante). Inoltre, controlla il link nel post per l'hook before_delete_post(), è tutto spiegato lì.

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

Questo richiede anche una query per $wpdb->postmeta altrimenti ci saranno valori orfani nella tabella postmeta che non verranno mai eliminati.

Howdy_McGee Howdy_McGee
9 giu 2016 01:45:25