Come implementare l'aggiornamento di un plugin WordPress che modifica il database?
Sviluppo un plugin WordPress, che ha diverse tabelle di database proprie. Il plugin crea queste tabelle quando viene attivato e le rimuove quando viene eliminato/disinstallato.
Devo implementare un processo di aggiornamento del plugin che aggiorni sia il codice del plugin che la struttura delle tabelle. Il caso più semplice sarebbe aggiungere una nuova colonna a una delle tabelle. Il caso più complesso sarebbe creare una nuova struttura di tabelle e aggiornare il contenuto di conseguenza.
Come consiglieresti di risolvere questo problema? Esistono funzioni integrate in WordPress che possono aiutare?

In breve, sì - la classe $wpdb
. Consulta il Codex per ulteriori informazioni.
Ogni volta che interagisci con una tabella personalizzata (o qualsiasi tabella, in realtà) dovresti passare attraverso $wpdb
- in particolare assicurati di conoscere il metodo prepare
che può aiutare a proteggere le query e prevenire injection.
Dovresti già essere familiare con questo, dato che dovresti usarlo per creare la tabella. Nel tuo hook di installazione dovresti avere qualcosa del genere:
$charset_collate = '';
if ( ! empty($wpdb->charset) )
$charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
if ( ! empty($wpdb->collate) )
$charset_collate .= " COLLATE $wpdb->collate";
//Crea tabella personalizzata
$sql_custom_table ="CREATE TABLE {$wpdb->prefix}my_table (
id bigint(20) unsigned NOT NULL auto_increment,
column_a varchar(255) default NULL,
column_b varchar(255) default NULL,
PRIMARY KEY (id)
) $charset_collate; ";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql_custom_table);
Questo codice viene effettivamente eseguito ogni volta che il plugin viene attivato (cioè non solo installato). Quindi verrà eseguito quando qualcuno aggiorna il plugin automaticamente. Nota: Se l'aggiornamento avviene sostituendo manualmente il plugin - allora non verrà eseguito - quindi dovrai attivare il codice sopra su admin_init
quando il tuo plugin viene aggiornato (memorizza il numero di versione nella tabella delle opzioni, confrontalo con la versione corrente).
Normalmente non vorresti che il comando SQL CREATE TABLE
venga eseguito ogni volta che aggiorni il plugin - è qui che entra in gioco dBDelta()
.
Prima di eseguire il comando sopra - verifica se la tabella esiste. Inoltre, controlla i tipi di colonna. Quindi se la tabella non esiste, la crea, se esiste ma alcuni tipi di colonna sono cambiati li aggiorna, e se una colonna non esiste - la aggiunge.
Sfortunatamente - se rimuovi una colonna dal codice sopra, non la rimuove automaticamente. Per rimuovere colonne/tabelle devi specificamente usare DROP
(controllando prima che esistano).

Il modo corretto per farlo al giorno d'oggi è includere lo schema come file nel sorgente del plugin e utilizzare la funzione integrata di WordPress dbDelta() per aggiornare il database secondo necessità utilizzando quello schema. Il codice effettivo richiesto è molto semplice:
$sql = file_get_contents( plugin_dir_path(__FILE__) . "/schema.sql" );
dbDelta( $sql );
Questo creerà e aggiornerà il database per te come richiesto. Quando ho controllato l'ultima volta, non eliminava le vecchie colonne inutilizzate, quindi dovresti gestirlo tramite un controllo di versione. Questa è una fantastica funzionalità di WordPress e un enorme risparmio di tempo. Fai attenzione quando crei il file schema.sql a copiare esattamente la spaziatura di un'esportazione dello schema mysql, poiché si dice che il codice dbDelta() sia molto esigente riguardo alla spaziatura. Dovresti anche testare la versione del database e, se non è la più recente, chiamare il codice sopra per aggiornarlo. Potresti anche aver bisogno di eseguire aggiornamenti specifici per coprire modifiche che dbDelta() non gestisce correttamente (ad esempio eliminare una colonna). È semplice scrivere un test logico if per verificare se la versione è stata aggiornata ed eseguire questi aggiornamenti manuali tramite $wpdb. Ad esempio, potresti eliminare una colonna che non è più utilizzata.
$installed_ver = get_option(MY_DB_VERSION);
$wpp = $wpdb->prefix . "mypluginname";
if ($installed_ver < 102)
$wpdb->query("ALTER TABLE ${wpp}_movies DROP nft_date");
if ($installed_ver < 107)
$wpdb->query("ALTER TABLE ${wpp}_movies CHANGE lastupdated "
. "lastupdated TIMESTAMP on update CURRENT_TIMESTAMP "
. "NOT NULL DEFAULT CURRENT_TIMESTAMP");
update_option(MY_DB_VERSION, $db_version);
Questo è semplificato da codice in esecuzione, mi scuso se l'ho rotto nel processo di semplificazione per la pubblicazione.
Tieni anche presente che a partire da WordPress 3.9.2, WordPress non esegue sempre l'hook di attivazione durante l'aggiornamento del plugin (specificamente, se viene eseguito un aggiornamento massivo dalla pagina Aggiornamenti della Dashboard).

In questi giorni ho iniziato a prendere la versione del DB dall'ora di modifica del file schema.sql. Questo significa che basta aggiornare il file schema.sql per causare un aggiornamento del database; non c'è bisogno di ricordarsi di modificare la versione del database. Qualcosa come: $db_version = filemtime("schema.sql");

Quindi, se l'ora del file cambia per qualcosa di esterno come lo spostamento su un altro server, l'mtime e la versione del db cambiano?

L'ora del file è sempre in GMT, e i server raramente differiscono di qualche secondo, quindi è quasi impossibile che venga attivato due volte per questo motivo. Comunque, anche se dovesse essere attivato di nuovo, non c'è alcun danno poiché viene eseguito una volta e fa un confronto con il database live, ovviamente senza cambiare nulla. Questa è la bellezza di dbDelta() - può essere eseguito più volte senza problemi. Bella domanda, grazie.
