Siamo nei guai!
Abbiamo importato i nostri prodotti su WooCommerce, ma per qualche motivo, ci ritroviamo con decine, centinaia di copie dello stesso prodotto con lo stesso SKU!
E adesso?
Adesso possiamo pagare un plugin che rimetta a posto le cose, oppure possiamo scrivere codice SQL che lo faccia per noi o, ancora, possiamo eliminare a mano ogni singolo prodotto duplicato: follia!
Oppure… possiamo finire su questo articolo, copiare il codice PHP qui riportato e… fare tutto gratis in pochi minuti… Tenendo però presente che questo codice non funziona se abbiamo prodotti variabili!
Chissà perché ritengo di conoscere quale sarà la vostra scelta!
L’immagine appena osservata mostra cosa succede lanciando il file PHP di cui troviamo il codice poco più in basso.
In pratica il programmino (scritto in modo molto, molto, molto banale, non me ne vogliano i colleghi “seri”!) cerca i prodotti con SKU identico. Se li trova, li mostra in basso nella sezione “DUPLICATES FOUND”. Si tratta di una tabella con due colonne: nella prima viene indicato lo SKU, nella seconda tutti gli ID dei prodotti con tale SKU (divisi da una virgola). A questo punto di tutti i prodotti con lo stesso SKU dobbiamo decidere se conservare quello inserito per primo o quello inserito per ultimo. Clicchiamo sul relativo pulsante e… preghiamo! 😀
<?php try { $tablePrefix = "wp_"; // <-CHANGE THIS $dbName = "DB_NAME"; // <-CHANGE THIS $dbUser = "DB_USER"; // <-CHANGE THIS $dbPassword = "DB_PASSWORD"; // <-CHANGE THIS $dsn = "mysql:host=localhost;dbname=".$dbName.";charset=utf8"; $PDOConnection = new PDO($dsn, $dbUser, $dbPassword); $PDOConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this_file = basename($_SERVER['SCRIPT_FILENAME']); $query = "SELECT meta_value as sku, COUNT(meta_value) as occurences, GROUP_CONCAT(DISTINCT post_id ORDER BY post_id SEPARATOR ',') post_id FROM ".$tablePrefix."postmeta WHERE meta_key = '_sku' AND meta_value != '' GROUP BY meta_value HAVING COUNT(meta_value) > 1 ORDER BY occurences DESC"; $res = $PDOConnection->query($query); $res2 = $PDOConnection->query($query); $error = ""; $htmlDuplicates = ""; $htmlProgress = ""; foreach ($res as $row) { $htmlDuplicates.= '<tr><td>'.$row['sku'].'</td><td>'.$row['post_id'].'</td></tr>'; } if (isset($_GET["keep"])) { $q = $_GET["keep"]; if ($q !== "" && $q == "first") { foreach ($res2 as $row) { $i=1; $productArray = explode(",", $row['post_id']); //print_r($productArray); //echo '<br>'; for ($i; $i<count($productArray); $i++) { //echo 'DELETE: ' . $productArray[$i]; $queryDEL="DELETE ".$tablePrefix."posts, ".$tablePrefix."postmeta, ".$tablePrefix."comments, ".$tablePrefix."commentmeta FROM ".$tablePrefix."posts LEFT JOIN ".$tablePrefix."postmeta ON ".$tablePrefix."postmeta.post_id = ".$tablePrefix."posts.ID AND ".$tablePrefix."postmeta.meta_key = '_sku' LEFT JOIN ".$tablePrefix."comments ON ".$tablePrefix."comments.comment_post_ID = ".$tablePrefix."posts.ID LEFT JOIN ".$tablePrefix."commentmeta ON ".$tablePrefix."commentmeta.comment_id = ".$tablePrefix."comments.comment_ID LEFT JOIN ".$tablePrefix."postmeta wpm2 ON wpm2.post_id = ".$tablePrefix."posts.ID WHERE ".$tablePrefix."posts.post_type = 'product' AND ".$tablePrefix."posts.ID=".$productArray[$i]; $res = $PDOConnection->query($queryDEL); $htmlProgress.=$queryDEL.'<br>'; } } } else if ($q !== "" && $q == "last") { foreach ($res2 as $row) { $i=0; $productArray = explode(",", $row['post_id']); for ($i; $i<count($productArray)-1; $i++) { $queryDEL="DELETE ".$tablePrefix."posts, ".$tablePrefix."postmeta, ".$tablePrefix."comments, ".$tablePrefix."commentmeta FROM ".$tablePrefix."posts LEFT JOIN ".$tablePrefix."postmeta ON ".$tablePrefix."postmeta.post_id = ".$tablePrefix."posts.ID AND ".$tablePrefix."postmeta.meta_key = '_sku' LEFT JOIN ".$tablePrefix."comments ON ".$tablePrefix."comments.comment_post_ID = ".$tablePrefix."posts.ID LEFT JOIN ".$tablePrefix."commentmeta ON ".$tablePrefix."commentmeta.comment_id = ".$tablePrefix."comments.comment_ID LEFT JOIN ".$tablePrefix."postmeta wpm2 ON wpm2.post_id = ".$tablePrefix."posts.ID WHERE ".$tablePrefix."posts.post_type = 'product' AND ".$tablePrefix."posts.ID=".$productArray[$i]; $res = $PDOConnection->query($queryDEL); $htmlProgress.=$queryDEL.'<br>'; } } } } } catch (PDOException $e) { $error = $e->getMessage(); if ($PDOConnection!=null) { $PDOConnection=null; } } ?> <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <title>Search and delete duplicate SKU</title> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> body { background-color: #222; color: #ccc; font-family: sans-serif; } #container { max-width: 800px; margin: 0 auto; } h1 { text-align: center; } h1 span { color: red; } h2 { text-align: center; border: thin solid #aaa; padding: 10px; border-radius: 10px; } #choose { border: thin solid #aaa; padding: 20px; border-radius: 10px; background-color: #ddd; color: #222; } #choose h2 { margin-top: 0; border: none; } #choose a { background-color: #222; border-radius: 10px; color: white; display: block; margin-bottom: 1rem; padding: 15px 10px; text-decoration: none; text-align: center; text-transform: uppercase; } #executed_query { font-size: 0.8rem; height: 70vh; overflow: auto; } table { width: 100%; } table th { text-align: left; } </style> </head> <body> <div id="container"> <header> <h1>Search and <span>delete</span><br>WooCommerce PRODUCTs<br>with duplicate SKUs</h1> </header> <section id="choose"> <h2>CHOOSE WHICH PRODUCT KEEP</h2> <p><strong>This script deletes products with identical SKUs.</strong><br> If there are n products with the same SKU, you can choose whether to keep the first product inserted or the last one. </p> <a href="./<?php echo $this_file ?>?keep=first">Keep the FIRST product</a> <a href="./<?php echo $this_file ?>?keep=last">Keep the LAST product</a> </section> <?php if ($error=="") {?> <section> <?php if ($htmlProgress!="") { ?> <h2>QUERY EXECUTED</h2> <div id="executed_query"><?php echo $htmlProgress ?></div> <?php }?> </section> <section> <h2>DUPLICATES FOUND</h2> <?php if ($htmlDuplicates!="") { ?> <table> <tr> <th>SKU</th> <th>PRODUCT IDs</th> </tr> <?php echo $htmlDuplicates ?> </table> <?php } else { ?> <p>Non ho trovato nessun SKU duplicato!</p> <?php }?> </section> <?php } else { echo '<p>SYSTEM CAN\'T WORK FOR THIS REASON:<br><p>'.$error.'</p>'; } ?> </div> </body> </html>
Ci si aspetta che in questa sede si abbia una minima dimestichezza con il codice…
In ogni caso, ecco cosa dobbiamo fare:
- creare un file di testo e incollare il codice qui sopra riportato;
- salvare poi il file con estensione .php;
- copiare il file nella root del nostro WordPress;
- richiamare quel file tramite protocollo http, del tipo “https://miodominio.it/miofile.php”.
Prima di fare questo, però, dobbiamo modificare i dati per connetterci al DB.
In particolare le seguenti righe DEVONO ESSERE MODIFICATE.
$tablePrefix = "wp_"; // <-CHANGE THIS $dbName = "DB_NAME"; // <-CHANGE THIS $dbUser = "DB_USER"; // <-CHANGE THIS $dbPassword = "DB_PASSWORD"; // <-CHANGE THIS
Bisogna inserire, rispettvamente:
- il prefisso delle tebelle di WordPress
- il nome del databse
- Il nome dell’utente che lo gestisce
- la password.
Queste informazioni si possono recuperare tutte all’interno del file wp-config.php di WordPress.
Al termine delle operazioni, il sistema elenca tutte le query eseguite.
Bene.
Lo so che mi volte bene, lo so… 😀
Non mi resta che augurarvi buona cancellazione massiva! 🙂
non funziona linea 25
Beh, Matteo, abbastanza utile come commento, no? 😀
Comunque… ho appena fatto copia/incolla del codice su un server qualunque ed è partito regolarmente. Poi mi dice che non può collegarsi al DB, ma quello è normale. Quindi non so cosa dirti…