Uno de los grandes errores de diseño en los orígenes de WordPress ha sido el presuponer que la base de datos estaban en Latin1 y a pesar de ello permitir escribir caracteres UTF-8. Si tienes problemas con esto, recomiendo leer el artículo completo antes de enfangarte con esta delicada operación.
Se han escrito RÍOS de artículos sobre el problema que esto ha provocado cuando con la llegada de WordPress 2.2 se pusieron serios y decidieron definir el charset en la configuración. El CODEX WordPress tiene un artículo: Converting Database Character Sets dedicado al tema, pero es muy teórico y no es de fácil comprensión. En el mismo (y en los artículos que he consultado) recomiendan el uso de el script A o B… pero cuando sigues el enlace te encuentras un 404, han terminado desapareciendo de internet. Bueno, todos no, existe un plugin majísimo que g30rg3_x colgó en el repositorio de WordPress que os comento luego.
Solución 1: no definir
[SIGT.net]
La “solución” mas sencilla, es no definir el charset en la configuración (comentando las dos líneas del wp-config.php). Con ello WordPress “magicamente” acierta el charset que tiene que usar (se supone que por defecto usa Latin1, a pesar de que al instalar crea la BBDD en UTF-8).
wp-config.php
define(‘DB_CHARSET’, ”);
define(‘DB_COLLATE’, ”);
Solución 2: conversión a binary y de ahí a utf-8
Como bien dicen en SIGt, la solución 1 no soluciona nada, sigues teniendo datos UTF-8 metidos en una BBDD latin1, lo cual no es bueno en general. Aquí nos enfangamos un poco y, como indica el CODEX, tenemos que convertir los campos texto a binary, cambiar el charset de las tablas a utf-8, y luego devolver los campos a su tipo original. Lo primero protege la integridad de los datos cuando se cambia el charset.
La receta:
- Hacer una copia de seguridad de la base de datos. (Viva mysqlump)
- Actualizar a la última versión de WordPress.
- Usar el plugin UTF-8 Database Converter (da un aviso de versiones, funciona correctamente si tienes WP superior a 2.2).
Solución 3: dar el cambiazo en la copia de seguridad
[Vía: Convert a MySQL DB from latin1 to UTF8]
En mi caso, la solución 2 no me funcionó. Así que restauré la BBDD al punto inicial con la copia de seguridad y continué probando.
pseudo-script bash (linux)
# Vocado copia de seguridad
mysqldump -u root -p –opt –default-character-set=latin1 –skip-set-charset DBNAME > DBNAME.sql
# Cambiazo de charset
sed -e ‘s/latin1/utf8/g’ -i ./DBNAME.sql
# Importación de BBDD
mysql -p –default-character-set=utf8 DBNAME < DBNAME.sql
Solución 4: volcado a tablas latin1 y cambio a utf-8
En mi caso, no podía hacer la solución 3, porque solo tenía un phpMyAdmin para acceder a mis datos y no podía forzar el charset a Latin1 en el dump. Así que restauré la BBDD al punto inicial con la copia de seguridad y continué probando.
No se porqué extraña razón, mis bases de datos decían estar en UTF-8, pero se comportaban como Latin1. Así que tenía que dar el cambiazo en sentido inverso, indicando que eran Latin1. Cambiar el dump la definición no era suficiente. Así, que decidí ñapear de otra manera (un poco a base de prueba y error): volcar los datos de las tablas en tablas Latin1 y sustituir éstas.
pseudo-script sql
— Crear tabla temp
CREATE TABLE table_temp LIKE table;
— Cambiar charset de temp
ALTER TABLE table_temp CONVERT TO CHARACTER SET latin1;
— Volcar datos
INSERT INTO table_temp SELECT * from table;
— Sustituir tabla
DROP TABLE table;
RENAME TABLE table_temp TO table;
Después, ya pasé el plugin UTF-8 Database Converter (bueno, en realidad añadí estas sentencias SQL al plugin en el primer foreach que recorre las tablas).
Os dejo aquí mi versión del plugin UTF-8 Database Converter versionado por mi (no tengo ni idea de como va el tema de la licencia Do What The Fuck You Want To, Version 2), espero no descolgarlo en muuucho tiempo.
Solución 5: convertir caracteres
Esta solución no la he tenido que aplicar, así que solo la dejo anotada. La idea es recorrer todos los campos tipo texto, encontrar todos los caracteres con problemas y convertirlos a su equivalente UTF-8. La función utf8_encode de php es tu amiga.
Recomendaciones finales:
- Hacer copia de seguridad de la base de datos.
- Probar en un entorno local todo lo que vayamos a hacer. Recordemos que hay que modificar dos entradas en la tabla wp_options: siteurl y home con las URLs locales.
PD: DailyCosas en breve migrará a WordPress 3.0 desde WP 2.0 y esto es el primer problema que hemos encontrado al preparar la migración y los cambios que vendrán.
August 5th, 2010 13:47
Si se opta por la solución 5, es más efectivo y dará menos problemas a largo plazo sustituir los caracteres acentuados y especiales por su entidad html equivalente. Es lo que hice con la migración de mi viejo blog.
Por cierto, ¿sabes de alguna aplicación o script que lo haga automáticamente? Hacerlo a mano con el buscar y reemplazar del editor de texto es un rollazo 😛
— Javi
August 5th, 2010 15:45
A mi la solución 4 me ha cambiado correctamente los caracteres a UTF-8.
Como dicen en el CODEX, la solución 5 se hace ocn el UTF8-Sanitize Plugin, que tiene una opción para recorrer los campos text y “sanearlos”.
http://www.prelovac.com/vladimir/ultimate-solution-to-weird-utf-character-encoding-problem
No lo he probado, no lo voy a probar…
Una solución paralela a la 5 es hacer un dump y tirar de iconv
http://blogofsysadmins.com/cambiar-la-codificacion-de-archivos-de-iso-8859-1-a-utf-8
October 8th, 2010 20:20
iconv -f ISO-8859-1 -t UTF-8 db.sql > db_utf8.sql
eso es simple y no toma nada de tiempo
October 8th, 2010 20:53
Hiper, a mi eso no me funcionó, sino que me dejó todo con caracteres rarunos. La culpa es del WP2, que estaba mal hecho. Gracias
October 10th, 2010 10:06
Bueno yo encontré tu post de casualidad, tenia una base de datos vieja que corría en mysql 4.0 de un phpnuke y estaba en latin, seguí las instrucciones de otra web y me quedo perfecto, ahora tengo todo en utf-8 unicode, tambien tuve problemas con zend, ultraedit, y notepad++, pero ya aprendi como lidiar e intercambiar de latin1 a utf-8, tambien baje fuentes unicode y etc, etc. ahora duermo, y suenio en utf8 jajajaj.