web-dev-qa-db-fra.com

Comment supprimer toutes les photos non utilisées

J'ai le problème actuel: je gère un site Web WordPress avec Woo Commerce et tous les quelques jours, j'actualise la liste des produits en supprimant et en important plus de 8 000 produits à la fois.

Maintenant, chaque fois que je reçois +/- 3500 produits supprimés de la base de données, je dois donc supprimer les photos et les vignettes de chacun d'entre eux. Je dois donc supprimer plus de 12 000 photos.

Utiliser un plugin n’est pas une option, ils gèlent/arrêtent tous de fonctionner, donc j’ai besoin de créer ma propre fonction/plugin et j’ai besoin d’un point de départ.

J'ai une liste avec les anciens produits et je les supprime comme ceci:

foreach($old_product_list as $oldproduct){

    $wpdb->show_errors();
    $delq = $wpdb->get_results(
                     "  DELETE a,b,c
                        FROM wp_posts a
                        LEFT JOIN wp_term_relationships b ON ( a.ID = b.object_id ) 
                        LEFT JOIN wp_postmeta c ON ( a.ID = c.post_id ) 
                        LEFT JOIN wp_term_taxonomy d ON ( d.term_taxonomy_id = b.term_taxonomy_id ) 
                        LEFT JOIN wp_terms e ON ( e.term_id = d.term_id )                    
                        WHERE a.post_title='".$mysqli->real_escape_string($oldproduct['name'])."' " );  

[.....]

1
Liviu ZeJah

En règle générale, je vous suggère d'essayer de vous en tenir le plus possible aux fonctions principales de Wordpress lorsque vous modifiez la base de données, car elles géreront automatiquement les données associées - par ex. supprime les méta-messages associés, les informations de taxonomie associées, etc. (Woocommerce stocke les données d'image de produit sous la forme de produit post_meta, voir ci-dessous pour plus de détails.) Cela pourrait ralentir les choses par rapport à l'accès direct à la base de données, résultat.

Inutile de dire que faites une sauvegarde de votre base de données avant d'essayer tout ça ...

Tout d’abord, vous devez travailler avec des identifiants de publication.

global $wpdb;
foreach ($old_product_list as $old_product) {
   $prod_names[] = $mysqli->real_escape_string($oldproduct['name']);
}

$prod_ids = $wpdb->get_results($wpdb->prepare("
                 SELECT ID FROM {$wpdb->prefix}posts 
                 WHERE post_type='product' AND post_title IN (%s)",
                 explode(',',$prod_names)));

Maintenant, il y a trois choses différentes que vous pouvez vouloir supprimer, en ordre croissant de 'destructivité':

  1. Supprimer les références aux identifiants d'image dans les produits post_meta
  2. Supprimez les publications 'attachées' associées à chaque image - cela supprimera les images de la galerie de médias Wordpress
  3. Supprimer les fichiers image réels du serveur

Point 1 . Celui-ci est facile. Mais pour le faire correctement , vous avez besoin d'utiliser les fonctions wordpress, comme le précisent les commentaires du code.

foreach ($prod_ids as $id) {
    // This will also remove all post_meta associated to the product
    // and apply any delete_post filters added by Woocommerce or other plugins
    // Second arg forces deletion, bypassing the trash
    wp_delete_post($id,true); 
} 

Points 2 et 3, cas simple.

Si vos images sont toutes uniques à chaque produit et ne sont liées à aucun endroit, leur post_parent sera le product_id. Vous pourrez donc utiliser cette version de https://wordpress.stackexchange.com/a/ 109803/40965 , modifié pour contourner la corbeille:

function delete_product_attachments($id) {
    if ('product' !== get_post_type($id)) return;

    $media = get_children(array(
        'post_parent' => $id,
        'post_type' => 'attachment'
    ));

    foreach ($media as $img) {
        unlink(get_attached_file($img->ID)); //delete files from server
        wp_delete_attachment($img->ID,true); //force post deletion, bypassing trash
    }
}

add_action('before_delete_post','delete_product_attachments');

La dernière ligne s'assure que cette fonction est appelée à chaque fois que wp_delete_post est appelé, vous n'avez donc pas besoin de changer la solution au point 1 ci-dessus.

Points 2 et 3, cas général. Si certaines images sont partagées par plusieurs produits (dont certaines ne sont peut-être pas supprimées du lot en cours) ou liées à d'autres publications, la solution ci-dessus va casser des choses.

C'est ici que nous devons comprendre comment Woocommerce gère les images de produits. Les images associées à un produit sont stockées en tant que post_meta '_thumbnail_id' et '_product_image_gallery' pour l'identifiant de publication du produit. _thumbnail_id est le post_id de l'image (poste avec post_type = 'attachment'); _product_image_gallery est une chaîne d'identifiants de publication d'image séparés par des virgules.

Juste pour commencer, voici comment obtenir tous les identifiants de post de pièce jointe à gérer.

$image_ids = $wpdb->get_col($wpdb->prepare("
                 SELECT meta_value FROM {$wpdb->prefix}post_meta
                  WHERE meta_key = '_thumbnail_id' AND post_id in (%s)",
                 explode(',',$prod_ids)));
$gallery_ids = $wpdb->get_col($wpdb->prepare("
                 SELECT meta_value FROM {$wpdb->prefix}post_meta
                  WHERE meta_key = '_product_image_gallery' AND post_id in (%s)",
                 explode(',',$prod_ids)));

$gallery_ids = explode(',',$gallery_ids); //get all ids in a single string
$gallery_ids = array_unique(implode(',',$gallery_ids));
$image_ids = array_merge($image_ids,$gallery_ids);
//do something with all $image_ids

Et voici la partie difficile: appliquez la solution ci-dessus uniquement aux images pouvant être supprimées en toute sécurité.

1
adelval