Aviones a reacción

Continuamos con la explicación técnica de lo que hice para conseguir fusionar los contenidos de nuestras webs en la web que estás viendo ahora. En la entrada anterior te expliqué que exportamos las bases de datos de las tres webs a fusionar, limpiamos sus contenidos para quedarnos sólo con las tablas relevantes y cómo cambiamos los prefijos de las tablas para así poder cargarlas todas en una misma base de datos conjunta.

Esta base de datos contiene las tablas que te muestro en la siguiente captura:

Tablas preparadas para realizar la fusión de blogs de Nelio.
Tablas preparadas para realizar la fusión de blogs de Nelio.

Puedes observar que hay tres bloques de tablas con prefijos correspondientes a las tablas de WPrincipiante, Nelio A/B Testing y la antigua web de Nelio Software. Se muestran también las tablas del WordPress multisitio destino, que es la instalación WordPress adónde vamos a mover los contenidos. Este es nuestro punto de partida.

En esta entrada te describiré la correspondencia (mapping, que dicen los ingleses) entre los contenidos de las tablas a migrar y las tablas de la nueva web. Esto no es más que la guía para poder programar las instrucciones y reglas del código de la migración. Puede parecer simple, pero es el punto más importante de todo el proceso de fusión de contenidos. Aquí es donde uno se la juega… ¡Espero que estés listo!

Qué hemos migrado y cómo lo hemos hecho

En nuestra migración de contenidos decidimos fusionar los contenidos de los blogs de WPrincipiante, Nelio A/B Testing y la antigua web de Nelio Software, tal y como ya te he indicado antes. Además, los contenidos en español (el blog de WPrincipiante) se separarán de los contenidos en inglés en la instalación WordPress destino. Para ello utilizamos dos subsitios (cuyos dominios son neliosoftware.com y neliosoftware.com/es/) en una instalación WordPress multisitio.

Los contenidos a migrar han sido usuarios, entradas, comentarios, categorías y etiquetas. Seguimos este orden por un tema de dependencias entre identificadores de contenidos. Empezamos por usuarios ya que estos no referencian a ningún otro contenido. Luego seguimos con las entradas, que referencian a los usuarios (autores). Y por último acabamos con los comentarios, que enlazan con entradas y usuarios, y las categorías y etiquetas, que mantienen enlaces con las entradas. Veamos el detalle para cada uno de estos.

Usuarios

Las tablas origen a migrar son:

  • abtesting_users y abtesting_usermeta,
  • neliosoftware_users y neliosoftware_usermeta,
  • wprincipiante_users y wprincipiante_usermeta.

Los contenidos de estas tablas (los usuarios de las tres webs) hay que moverlos a las tablas wp_users y wp_usermeta de la instalación destino. Ten en cuenta que en un WordPress multisite las tablas de usuarios son compartidas por todas las instalaciones.

En nuestro caso, los únicos usuarios que teníamos en cada web eran los usuarios de los diferentes autores de entradas. Por tanto, el número es muy pequeño (un total de 11 usuarios diferentes, teniendo en cuenta todas las webs).

Lo primero que hice es crear a mano, a través del Escritorio de WordPress, tres usuarios en la instalación multisite (para los tres co-fundadores de Nelio) y darles permisos de Editor en ambos subsitios (inglés y español). Esto es así ya que los tres usuarios ya existían en las tres webs origen a fusionar y tenían que seguir en la instalación destino. Así que de estos tres usuarios ya no tenía que preocuparme en el código de la migración. Además, teniendo listos estos usuarios, mientras yo realizaba el código de la migración también mis compañeros podían avanzar con los contenidos nuevos de la web.

En cuanto al resto, la forma de proceder es muy sencilla. Tan sólo tenemos que hacer un código que realice una consulta a las tablas users origen (abtesting_users, neliosoftware_users y wprincipiante_users) e inserte cada usuario encontrado en la tabla wp_users del multisite. Eso sí, en la consulta hemos de indicar que no nos devuelva también los usuarios de los co-fundadores, ya que estos ya los hemos creado a mano.

Seguramente te estarás preguntando qué pasa si hay dos usuarios que tienen el mismo identificador numérico en dos tablas diferentes. Es decir, si tengo el usuario john.wayne en abtesting_users cuyo identificador es 3 y luego tengo el usuario mary.smith en neliosoftware_users también con el identificador igual a 3, seguramente voy a recibir un error cuando trate de insertar el segundo, ya que el identificador 3 ya está usado y debe ser único.

Para evitar este problema, que veremos que ocurrirá también con los demás tipos de contenidos a migrar, lo que hacemos es usar un desplazamiento (offset, en inglés). Esto no es más que sumar un cierto número al identificador para evitar colisiones. Por tanto, si después de migrar los usuarios de la tabla abtesting_users tenemos que el identificador usado más alto es el número 7, pues ese será el desplazamiento que sumaremos a los identificadores de la tabla neliosoftware_users. En el ejemplo anterior, migraríamos el usuario john.wayne con identificador 3, pero el usuario mary.smith se migraría con un nuevo identificador: el 10 (identificador original 3 + desplazamiento 7).

Hay que ir con mucho cuidado con el tema de los desplazamientos. Siempre hay que aplicar los mismos en cada tabla para evitar perder enlaces entre datos que están en tablas diferentes. Por ejemplo, cuando tengamos que migrar las entradas de Nelio Software (de la tabla neliosoftware_posts) tendremos que sumar el desplazamiento también en la columna post_author, que es la que enlaza la entrada con el usuario de la tabla neliosoftware_users. Así, una entrada que anteriormente pertenecía al autor mary.smith con identificador 3, deberá tener como autor final el usuario con identificador 10 (el nuevo ID de nuestra amiga Mary). Sino, podríamos estar asignando entradas a usuarios erróneos o incluso inexistentes…

Por otro lado, para el caso de las tablas abtesting_usermeta, neliosoftware_usermeta y wprincipiante_usermeta lo que hemos hecho es muy similar a lo que hemos hecho con las tablas de usuarios. Estas tablas incluyen meta-información sobre los usuarios, incluyendo sus perfiles sociales, descripción, información personal adicional, etc. En definitiva, muchos datos que nos interesa mantener, pero también muchos que no. Hemos creado un código que revisa cada fila de estas tablas y si el meta-dato es relevante para nosotros, lo mueve a la tabla wp_usermeta destino (sin olvidar aplicar el desplazamiento, cuando convenga).

Filas de la tabla abtesting_usermeta para el usuario con identificador número 4.
Filas de la tabla abtesting_usermeta para el usuario con identificador número 4. Ya ves que hay muchas filas con metadatos basura.

Para definir que un meta-dato es relevante hemos consultado la columna meta_key, que indica el nombre único del meta-dato. Todas aquellas filas que contienen información antigua o meta-datos creados por plugins viejos que ya no usamos los hemos descartado y no los hemos transferido a wp_usermeta. Mi consejo aquí es que cojas un usuario en concreto y mires todas las entradas de esta tabla para él (tienes una muestra en la imagen anterior) y te quedes sólo con aquello que realmente tenga sentido. Con esto podrás extrapolar a todos los demás usuarios. Encontrarás mucha basura, eso seguro. ¡Ah! Y no te olvides de sumar el desplazamiento correcto a la columna user_id ?

Otro detalle a tener en cuenta (sí, los detalles son la fuente principal de errores en una migración) es el tema de los permisos de los usuarios. Existen dos filas de meta-datos en las tablas usermeta cuyos valores de la columna meta_key son wp_capabilitieswp_user_level. El tema aquí está en que si queremos dar permisos para el subsitio principal (neliosoftware.com, en nuestro caso), no hemos de hacer nada. Pero si queremos dar permisos para cualquier otro subsitio, por ejemplo neliosoftware.com/es/, cuyo identificador de sitio es el 3, tendremos que cambiar el valor de meta_key para esas filas por wp_3_capabilitieswp_3_user_level. De otra forma, el usuario no tendrá permisos para acceder al subsitio. Este reemplazo lo hemos hecho para los usuarios que teníamos en WPrincipiante, ya que queremos que tengan acceso al subsitio en español, con identificador 3.

Después de todo esto, ya tenemos los usuarios listos en nuestra instalación destino. Sé que ha sido un poco largo y complejo, pero espero que los conceptos básicos estén claros, ya que lo que acabamos de ver se va repitiendo en los próximos pasos. Resumiendo, pues, quédate con la idea de que hay que leer las tablas e insertar sólo aquello relevante.

Entradas

Las tablas que tenemos que mirar para mover las entradas de los tres blogs originales a la instalación multisitio son:

  • abtesting_posts y abtesting_postmeta,
  • neliosoftware_posts y neliosoftware_postmeta,
  • wprincipiante_posts y wprincipiante_postmeta.

Aquí tenemos que diferenciar entre contenidos en inglés (las tablas de Nelio A/B Testing y Nelio Software), que irán a las tablas wp_posts y wp_postmeta, y contenidos en español (las tablas de WPrincipiante), que irán a las tablas wp_3_posts y wp_3_postmeta del subsitio en español.

El procedimiento a seguir es el mismo que para el caso de los usuarios. Lo primero es seleccionar las filas de las tablas de posts (abtesting_posts, neliosoftware_posts y wprincipiante_posts) que se corresponden con entradas publicadas. En nuestra migración no necesitamos mantener las páginas, por lo que nos tenemos que quedar sólo con aquellas filas que tienen la columna post_type con el valor 'post' y que además tienen la columna post_status con el valor 'publish'.

Sin embargo, las tablas de entradas también almacenan los meta-datos de los archivos multimedia que podemos encontrar en la biblioteca de medios de WordPress. Y esto también lo queremos migrar, para no dejarnos atrás las imágenes. Por tanto, también hemos de quedarnos con las filas que tienen la columna post_type con el valor 'attachment'.

En lenguaje SQL, la consulta que tendríamos que hacer sería tal que así:

SELECT * 
FROM prefijo_posts
WHERE (post_type = 'post' AND post_status = 'publish') OR
      (post_type = 'attachment')

Eso si, tendríamos que cambiar prefijo_posts por abtesting_posts, neliosoftware_posts y wprincipiante_posts cada vez para tratar las tres tablas.

De nuevo, es muy importante que no nos olvidemos de los desplazamientos. Al igual que con los usuarios, en las tablas de entradas tenemos las columnas ID y post_author. La primera es el identificador de la fila en la tabla posts y la segunda es una referencia al usuario autor. Para evitar colisiones entre filas, tendremos que sumar un nuevo desplazamiento a la columna ID de cada tabla de posts. Y también tendremos que sumar el mismo desplazamiento que habíamos usado cuando procesamos los usuarios a la columna post_author. Recuerda apuntarte los desplazamientos usados ya que los tendremos que aplicar también para los comentarios y las categorías y etiquetas.

Otro aspecto a tener en cuenta es la columna guid. WordPress usa el valor de esta columna para generar correctamente los feed RSS de tu web. El valor que existe originalmente en esta columna hay que cambiarlo para que sea el correcto en la nueva instalación WordPress multisitio. Para ello, hemos seguido las siguientes reglas:

Para cada fila f de wprincipiante_posts:
si f.post_type = 'post' entonces
  f.guid = 'https://neliosoftware.com/es/?p=' + f.ID
si f.post_type = 'attachment' entonces
  f.guid = f.guid->reemplazar('http://wprincipiante.es/wp-content/uploads/',  
                   'https://neliosoftware.com/es/wp-content/uploads/sites/3/')
Para cada fila f de abtesting_posts o de neliosoftware_posts:
si f.post_type = 'post' entonces
  f.guid = 'https://neliosoftware.com/?p=' + f.ID
si f.post_type = 'attachment' entonces
  f.guid = f.guid->reemplazar('*/wp-content/uploads/', 
                   'https://neliosoftware.com/wp-content/uploads/')

Parece muy complicado, pero no lo es. Sólo hemos de tener en cuenta que si estamos procesando una entrada (post_type = 'post') lo que hay que hacer es poner como guid la URL corta de la entrada. Esta URL se construye añadiendo el parámetro p con el ID final (incluido el desplazamiento) al dominio, como puedes ver en las reglas anteriores.

Por otro lado, si estamos procesando un archivo (post_type = 'attachment') lo que tenemos que hacer es reemplazar la primera parte de la URL hasta /wp-content/uploads/ por https://neliosoftware.com/es/wp-content/uploads/sites/3/ en el caso de WPrincipiante y por https://neliosoftware.com/wp-content/uploads/ en los demás casos. Esto es así ya que el subsitio en español almacena las imágenes en un subdirectorio correspondiente al identificador del subsitio dentro de wp-content/uploads/.

Con todo esto listo, ya podremos insertar cada fila en la tabla wp_posts (para el caso del contenido en inglés) o en la tabla wp_3_posts (para el caso del contenido en español). Pero no hemos acabado todavía, ya que tenemos que procesar las tablas postmeta.

Estas tablas, al igual que las usermeta, contienen metadatos de las filas de las tablas posts. La manera de proceder aquí es la misma, hay que mirar las filas de postmeta correspondientes a una fila de una tabla posts concreta y decidir cuáles son los metadatos que vamos a mover y cuáles vamos a ignorar.

No debemos olvidarnos de aplicar el desplazamiento adecuado a la columna post_id, que hace referencia a la columna ID de posts. Y otra cosa a tener en cuenta también es que a las filas de postmeta cuya columna meta_key tenga el valor ‘_thumbnail_id' también necesitarán un desplazamiento, ya que ese campo indica qué imagen destacada tiene asignada una entrada cualquiera y hace referencia a un attachment en la tabla posts.

Ahora sí, ya tenemos todo listo para insertar estas filas en wp_postmeta o wp_3_postmeta según corresponda. Y por tanto, los contenidos de entradas y meta-información de archivos multimedia ya están fusionados en la instalación WordPress multisitio de destino.

Comentarios

Llegados a este punto, nos queda mover los comentarios. Esta parte es bastante sencilla ya que tendremos que mirar las siguientes tablas:

  • abtesting_comments y abtesting_commentmeta,
  • neliosoftware_comments y neliosoftware_commentmeta,
  • wprincipiante_comments y wprincipiante_commentmeta.

Afortunadamente, las tablas commentmeta no contenían información destacable, así que las ignoré por completo. La consulta que hice para obtener los comentarios a migrar es la siguiente en SQL:

SELECT * 
FROM prefijo_comments
WHERE comment_approved <> 'spam'

De este modo evitamos procesar comentarios marcados como spam. Y lo que queda es insertar cada comentario resultante de la siguiente consulta. Pero ojo, hay que aplicar también desplazamientos para evitar colisiones o errores con referencias ?

Primero, necesitamos un nuevo desplazamiento para aplicar a la columna comment_ID, que es el identificador del comentario. Luego aplicaremos el desplazamiento de posts a la columna comment_post_ID, que es la que enlaza el comentario con la entrada pertinente. Y por último, aplicaremos el desplazamiento de users a la columna user_id, que es la que enlaza el comentario con un usuario de WordPress.

Con esto ya tendremos los comentarios listos y además habremos dejado atrás todos los comentarios basura existentes.

Categorías y etiquetas

Para el caso de las categorías y etiquetas el procedimiento a seguir ha sido muy diferente. En las webs originales nos dimos cuenta de que teníamos demasiadas categorías y una infinidad de etiquetas. Como ya hemos explicado alguna vez, las categorías y etiquetas han de ser útiles para que los visitantes puedan encontrar con mayor facilidad los contenidos que están buscando.

En la instalación final hemos decidido quedarnos únicamente con 4 categorías (Comunidad, Marketing Online, WordPress y Negocio) y reducir el número de etiquetas hasta quedarnos sólo con 25. Además, el plan es no crear ni categorías adicionales ni etiquetas a partir de ahora (a no ser que tengamos una necesidad extrema de hacerlo). La nueva estructura de categorías y etiquetas la hemos creado a mano a medida que la íbamos consensuando mediante el Escritorio de WordPress.

Una vez establecidas cuáles serían nuestras nuevas nuevas categorías y etiquetas, había que decidir cuál sería la correspondencia entre las antiguas y las nuevas. Esto no fue nada fácil… pero creo que hemos conseguido un resultado bastante bueno. Sea cual sea la correspondencia que escojas, al final tendrás una serie de reglas como las siguientes:

si entrada contiene categoría antigua C1, C2, C3, ... o CN
entonces aplicar categoría nueva X
si entrada contiene etiqueta antigua T1, T2, T3, ... o TN
entonces aplicar etiqueta nueva Y

que te permitirán volver a clasificar tus entradas con las nuevas jerarquías. En nuestro caso, generamos más de 200 reglas (que te voy a ahorrar) y cuyo resultado repasamos a mano. En definitiva, lo relevante de este punto es disponer de una función en tu código que sea capaz de mirarse las tablas terms, term_taxonomy y term_relationships y sepa darte las categorías y etiquetas asociadas con una entrada de la tabla posts.

Una vez tenemos esto es fácil aplicar las reglas en orden para decidir las etiquetas y categorías a enlazar en la nueva web. Con esto, para insertar la nueva relación entre la entrada y la etiqueta o categoría hay que crear una nueva fila en la tabla wp_term_relationships o wp_3_term_relationships (según estemos con un contenido en inglés o español) de forma que la columna object_id tenga como valor el identificador de la entrada en la tabla posts. Y la columna term_taxonomy_id tenga como valor el identificador del término (etiqueta o categoría) en la tabla term_taxonomy.

La gestión de taxonomías en WordPress es un poco complicada y necesitarás ciertos conocimientos de cómo se guardan las etiquetas y categorías en las tablas de la base de datos de WordPress para poder migrar cosas así.

Y hasta aquí hemos llegado

Ha sido duro, ¿verdad? Ya te dije que esta parte iba a ser crucial y que los detalles son la clave para que todo acabe fusionado como toca, sin sorpresas. Me alegro de que hayas llegado hasta aquí y te doy las gracias por tu tiempo leyendo el artículo. Por lo menos espero que hayas aprendido algo nuevo o entiendas mejor que una migración es algo complejo.

En la tercera (y última ?) parte de esta entrada seguiremos justo donde nos hemos quedado ahora. Te explicaré los post-procesos que hemos tenidos que hacer después de mover los contenidos para limar ciertos aspectos y dejarlo todo impecable. Y, como no podía faltar, te contaré los problemas que hemos tenido (porque sí, los hemos tenido ?), cómo nos han afectado y cómo los hemos solucionado.

Será una entrada muy interesante, así que te espero allí. Y si tienes dudas sobre algún tema de los explicados hasta aquí ya sabes que puedes dejarme un comentario más abajo.

Imagen destacada de Marc Wieland.

3 respuestas a «Cómo fusionar múltiples blogs en uno sólo – el caso de Nelio (2/3)»

  1. […] Cómo fusionar múltiples blogs en uno sólo – el caso de Nelio (2/3) Hemos hablado en anteriores ocasiones de la decisión de Nelio de fusionar todos sus blogs (incluido WPrincipiante) en uno solo. A nivel teórico es una fantástica idea, pero a nivel técnico puede ser toda una pesadilla. Merece la pena ver el proceso llevado a cabo para terminar con un final feliz. […]

  2. Avatar de jesus
    jesus

    hola, he realizado una fusion de muchos blogs que tenia de viajes y los he fusionado en 1 solo.
    he utilizado importar y exportar y en los referente a los post todo a ido bien.
    El problema me surge con las imagenes.
    tengo casi 8000 imagenes que via FTP subi a la carpeta uploads
    pero aunque se ven dentro de los post, no se ven en portada, ni estan en la biblioteca de medios
    encontre un plugin que se supone que los subia a la biblioteca de medios, pero con tal cantidad de imagenes se queda bloqueado
    el plugginb es :

    Añadir Desde Servidor

    alguien sabe algun metodo para que las imagenes me salgan en la biblioteca?

    1. Avatar de Antonio Villegas

      Hola Jesus. ¿Hiciste tú la migración? En tal caso, moviste las bases de datos incluyendo las filas de attachments? Es muy posible que no hicieras (tú o quien se encargara de ello) bien esta parte. Por esto no aparecen las imágenes en la biblioteca de medios. O bien utilizando ese plugin poco a poco vas añadiendo las imágenes, o si todavía tienes los exports de las bases de datos, contacta con un profesional de tu zona que te pueda ayudar a migrar los attachments.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

He leído y acepto la política de privacidad de Nelio Software

Tus datos personales se almacenarán en SiteGround y serán usados por Nelio Software con el único objetivo de publicar tu comentario aquí. Con el envío de este comentario, nos das el consentimiento expreso para ello. Escríbenos para acceder, rectificar, limitar o eliminar tus datos personales.