Tengo el siguiente código para crear una tabla:
$sql = "CREATE TABLE " . $table_name . "("
. "id mediumint(9) NOT NULL AUTO_INCREMENT, "
. "product_id mediumint(9) DEFAULT 0 NOT NULL,"
. "name_type mediumint(9) NOT NULL, "
. "name_key varchar(48) NOT NULL, "
. "valid_until datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, "
. "created_at datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, "
. "updated_at datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, "
. "UNIQUE KEY id (id)"
. ")" . $charset_collate. ";";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
Está funcionando y la tabla creada.
Ahora necesito actualizar la tabla y agregar una nueva columna (sites_list):
$sql = "CREATE TABLE " . $table_name . "("
. "id mediumint(9) NOT NULL AUTO_INCREMENT, "
. "product_id mediumint(9) DEFAULT 0 NOT NULL,"
. "name_type mediumint(9) NOT NULL, "
. "name_key varchar(48) NOT NULL, "
. "sites_list longtext, "
. "valid_until datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, "
. "created_at datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, "
. "updated_at datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, "
. "UNIQUE KEY id (id)"
. ")" . $charset_collate. ";";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
Pero esto no funciona.
Y tengo un error:
WordPress database error: [Table 'table_name' already exists]
¿Qué es incorrecto?
Gracias.
Ha utilizado la función dbDelta incorrectamente.
-
Debe poner cada campo en su propia línea en su declaración SQL.
-
Debe tener dos espacios entre las palabras PRIMARY KEY y la definición de su clave principal.
-
Debe utilizar la palabra clave CLAVE en lugar de su sinónimo ÍNDICE y debe incluir al menos una CLAVE.
El código en sí de la función dbDelta es muy complejo. Pero con prueba y error, noté algunos comportamientos de la función dbDelta actualizar comportamiento:
- No cambia el nombre de la columna Clave principal
- No elimina una columna.
- Si intenta cambiar el nombre de una columna anterior, simplemente creará una nueva columna y mantendrá la anterior.
Explicación larga
dbDelta es una función que la gente suele decirle que se conecte a register_activation_hook
, pero esto no se activa con las actualizaciones de complementos, por lo que no crearía las tablas para los usuarios que están actualizando una instalación existente. Entonces, lo primero que debe hacer para que las actualizaciones de dbDelta funcionen es conectarlo admin_init
.
Sin embargo, esta es una función bastante pesada, por lo que solo debe ejecutarse cuando sea necesario. Para ello, puede mantener un my_plugin_db_version
en la base de datos, y utilícelo para verificar si debe ejecutar dbDelta o no.
Si ya tiene una opción cargada automáticamente, es aún mejor usarla, ya que la verificación no tendrá un impacto en el rendimiento, ya que las opciones cargadas automáticamente se cargan en la memoria al comienzo del ciclo de vida de WordPress.
Esto, en código, se puede expresar como:
add_action('admin_init', 'my_plugin_maybe_run_delta');
function my_plugin_maybe_run_delta() {
// Here we are not using an existing autoloaded option to keep the example short
$dbVersion = get_option('my_plugin_db_version');
// Early bail: No need to run dbDelta
if ($dbVersion === '1.0.0') {
return;
}
// dbDelta here...
// Now set the db version so it can early bail next time...
update_option('my_plugin_db_version', '1.0.0', false);
}
Ahora supongamos que tengo este dbDelta en la versión 1.0 de mi complemento:
global $wpdb;
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
$tableName = $wpdb->prefix . 'foo';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $tableName (
id bigint(20) NOT NULL AUTO_INCREMENT,
event longtext NOT NULL,
PRIMARY KEY (id)
) $charset_collate;";
dbDelta($sql);
// Some error happened during dbDelta.
if (!empty($lastErrorBefore) && $lastErrorBefore !== $wpdb->last_error) {
// handle error
}
Esto produce el siguiente DDL en la base de datos:
CREATE TABLE `wp_foo` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`event` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Ahora decido cambiar el nombre id
a event_id
así que cambio el dbDelta y libero la versión 1.1 del complemento:
$sql = "CREATE TABLE $tableName (
event_id bigint(20) NOT NULL AUTO_INCREMENT,
event longtext NOT NULL,
PRIMARY KEY (event_id)
) $charset_collate;";
Este delta no cambiará la estructura de la base de datos para los usuarios que están actualizando el complemento, tendrán la clave principal como id
mientras que las nuevas instalaciones tendrán la clave principal como event_id
:
CREATE TABLE `wp_foo` (
`event_id` bigint(20) NOT NULL AUTO_INCREMENT,
`event` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Entonces regla #1 de dbDelta: No cambia el nombre de la columna Clave principal.
Ahora, en la versión 1.2, quiero cambiar el nombre event
a events
entonces modifico el dbDelta así:
$sql = "CREATE TABLE $tableName (
event_id bigint(20) NOT NULL AUTO_INCREMENT,
events longtext NOT NULL,
PRIMARY KEY (event_id)
) $charset_collate;";
Esto producirá el siguiente resultado para los usuarios que actualicen de 1.1 a 1.2:
CREATE TABLE `wp_foo` (
`event_id` bigint(20) NOT NULL AUTO_INCREMENT,
`event` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
`events` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Al producir el siguiente resultado para instalaciones nuevas:
CREATE TABLE `wp_wpstg_analytics` (
`event_id` bigint(20) NOT NULL AUTO_INCREMENT,
`events` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`event_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Al producir el siguiente resultado para los usuarios que usan el complemento desde 1.0:
CREATE TABLE `wp_wpstg_analytics` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`event` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
`events` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Lo cual es un comportamiento bastante razonable cuando lo piensas. Si cambia el nombre de la columna event
a events
, aún puede migrar los datos de la columna anterior a la nueva para instalaciones anteriores. Solo recuerde nunca cambiar el nombre de la columna asignada como clave principal.
El error es bastante claro. No puede crear la tabla porque ya existe. probablemente quieras
ALTER TABLE
oCREATE TABLE IF NOT EXISTS
– naththedeveloper
22 de marzo de 2016 a las 16:08
Sí, esto será genial, pero del códice: La función dbDelta examina la estructura de la tabla actual, la compara con la estructura de la tabla deseada y agrega o modifica la tabla según sea necesario, por lo que puede ser muy útil para las actualizaciones.. https://stackoverflow.com/questions/36159055/table-not-updating-with-wordpress-dbdeltacodex.wordpress.org/… creo que el uso dbdelta más correctamente para actualizar el complemento
– Eugenio
22 de marzo de 2016 a las 16:28
Este problema probablemente se deba a que sus campos no están realmente en líneas separadas (esta es una de las “condiciones” establecidas por la función. La razón de esto es que está concatenando la cadena y esto en realidad dará como resultado una sola línea. I Agregaré una respuesta e intentaré explicar esto un poco mejor.
– naththedeveloper
23 de marzo de 2016 a las 7:48
Estoy tratando de eliminar la concatenación, pero nada cambió. El error es el mismo.
– Eugenio
25 de marzo de 2016 a las 5:34