Cambiar dominio en WordPress: WP-CLI search-replace sin romper datos serializados

Cambiar dominio en WordPress: WP-CLI search-replace sin romper datos serializados

Última verificación: 14 de octubre de 2026
26 min de lectura
Tutorial
Arquitectura de servidores

Pasar un sitio WordPress del entorno de desarrollo al dominio de producción, cambiar el nombre de la marca o instalar un certificado SSL (pasar de HTTP a HTTPS) son tareas rutinarias de cualquier administrador o desarrollador. A primera vista la operación parece trivial: exportar la base de datos a un archivo .sql, abrirlo en un editor de código, usar “Buscar y reemplazar” y volver a importarlo. O lanzar una consulta SQL rápida en phpMyAdmin.

Hacer eso sobre la base de datos de producción de WordPress termina con el sitio roto al instante. Desaparecen los widgets del pie y de las barras laterales, los ajustes de colores y tipografía del tema vuelven a sus valores por defecto, los campos avanzados (ACF) devuelven valores vacíos y la configuración de los plugins de comercio electrónico se pierde.

La causa está en la forma en que WordPress y sus plugins guardan estructuras de datos complejas en una base relacional MySQL o MariaDB. La documentación de WordPress lo advierte sin rodeos: una búsqueda y sustitución simple sobre toda la base de datos puede dañar la serialización, porque algunos temas y widgets guardan la URL junto con su longitud (Migrating WordPress, developer.wordpress.org). Entender la serialización de PHP y dominar las herramientas adecuadas, sobre todo la interfaz de línea de comandos WP-CLI, es la base para gestionar sitios WordPress con seguridad.


#Qué son los datos serializados en la base de datos de WordPress

Las bases de datos SQL relacionales están pensadas para guardar datos escalares: números, cadenas cortas o fechas. WordPress, sin embargo, necesita a menudo guardar en una sola fila una estructura compleja y multidimensional, por ejemplo un array con la lista de widgets activos, su orden, los iconos asignados y sus parámetros.

En lugar de crear decenas de tablas normalizadas adicionales para cada plugin, los creadores de WordPress optaron por una función nativa de PHP: serialize().

// Array de configuración de un tema en PHP
$theme_settings = array(
    'site_name'    => 'Mi Tienda WordPress',
    'logo_url'     => 'https://dominio-antiguo.es/logo.png',
    'contact_mail' => '[email protected]'
);

// Resultado de serialize($theme_settings)
// Guardado tal cual en la columna option_value de la tabla wp_options:
a:3:{s:9:"site_name";s:19:"Mi Tienda WordPress";s:8:"logo_url";s:35:"https://dominio-antiguo.es/logo.png";s:12:"contact_mail";s:26:"[email protected]";}

#Cómo leer una cadena serializada

Fijémonos en el fragmento que representa la URL del logotipo:

s:35:"https://dominio-antiguo.es/logo.png";

Cada elemento del formato serializado de PHP tiene una estructura estricta:

  • s indica el tipo de dato: string (cadena de caracteres).
  • 35 es la longitud declarada de la cadena (el número exacto de bytes).
  • "https://dominio-antiguo.es/logo.png" es el valor, entre comillas.

La pieza clave es el número 35. Al leer los datos de la base, PHP llama a la función unserialize(). El analizador de PHP no busca la comilla de cierre a ciegas, sino que cuenta exactamente 35 bytes desde el punto indicado.

#Por qué REPLACE de SQL rompe los datos serializados

Ejemplo: el sitio se migra a un dominio nuevo y más largo, https://dominio-nuevo-bastante-mas-largo-empresa.es. La nueva URL del logotipo es https://dominio-nuevo-bastante-mas-largo-empresa.es/logo.png, con 60 caracteres.

Si ejecutas la consulta SQL tradicional:

-- ERROR CRÍTICO: esta consulta destruye la serialización
UPDATE wp_options 
SET option_value = REPLACE(option_value, 'https://dominio-antiguo.es', 'https://dominio-nuevo-bastante-mas-largo-empresa.es');

En la base de datos quedará esta cadena:

s:35:"https://dominio-nuevo-bastante-mas-largo-empresa.es/logo.png";

Qué ocurre cuando un visitante abre la página:

  1. WordPress lee la fila de la base de datos y la pasa a unserialize().
  2. La función lee la cabecera s:35 y espera exactamente 35 caracteres.
  3. PHP corta los primeros 35 caracteres de la nueva URL y, en lugar de la comilla de cierre y el punto y coma obligatorios, encuentra letras sueltas dentro de la cadena.
  4. El analizador de PHP lanza el aviso PHP Notice: unserialize(): Error at offset... y devuelve false.
  5. El tema o el plugin recibe false en lugar del array de opciones que esperaba.
  6. WordPress da por hecho que los datos no existen y restablece los ajustes de fábrica del tema o elimina los widgets.

#Dónde guarda WordPress las URLs en la base de datos

Las URLs de una instalación de WordPress no están en un solo sitio. Están repartidas entre varias tablas del sistema y las tablas que crean los plugins:

graph TD
    A["Base de datos de WordPress"] --> B["wp_options"]
    A --> C["wp_posts"]
    A --> D["wp_postmeta"]
    A --> E["wp_comments / wp_commentmeta"]
    A --> F["wp_usermeta"]
    A --> G["Tablas de plugins (WooCommerce, formularios, SEO)"]
    
    B --> B1["siteurl y home (direcciones principales)"]
    B --> B2["sidebars_widgets (serializado)"]
    B --> B3["theme_mods (serializado)"]
    
    C --> C1["post_content (enlaces, imágenes)"]
    C --> C2["post_excerpt"]
    C --> C3["guid (NO cambiar en entradas publicadas)"]
    
    D --> D1["_elementor_data (JSON escapado)"]
    D --> D2["_wp_attached_file (rutas de medios)"]
    D --> D3["Campos ACF (serializados)"]

#1. La tabla wp_options

Es la tabla de configuración más importante. Contiene dos registros críticos para que el sitio funcione:

  • siteurl: indica dónde están físicamente los archivos de WordPress (la ruta del núcleo).
  • home: indica la dirección principal del sitio que los usuarios escriben en el navegador.

Además guarda en forma serializada:

  • sidebars_widgets: la disposición de los widgets en barras laterales y pies de página.
  • theme_mods_[nombre_del_tema]: colores, cabecera, tipografía y logotipo del personalizador (Customizer).
  • Los ajustes de plugins de SEO (Rank Math, Yoast), de seguridad y de caché.

#2. La tabla wp_posts

Guarda el contenido de entradas, páginas, productos de WooCommerce y elementos de la biblioteca de medios.

  • La columna post_content: contiene enlaces absolutos a otras páginas, etiquetas <img> incrustadas, enlaces a archivos PDF y los comentarios de bloque de Gutenberg.
  • La columna guid (Globally Unique Identifier): el identificador único de la entrada. Regla importante: la documentación de WordPress dice: “Nunca, jamás, cambie el contenido de la columna GUID, bajo ninguna circunstancia” (Migrating WordPress, developer.wordpress.org, traducción propia). La columna guid no debe cambiarse porque los lectores de feeds RSS la usan para detectar artículos nuevos. Si cambias el guid, los lectores tratarán todas las entradas antiguas como nuevas y volverán a avisar a los suscriptores.

#3. La tabla wp_postmeta

Contiene atributos adicionales de entradas y páginas. Aquí van los arrays serializados de los campos de Advanced Custom Fields (ACF), los metadatos de los adjuntos (_wp_attachment_metadata) y la configuración de constructores de páginas como Elementor o Divi.

#4. Las tablas wp_usermeta y wp_comments

Contienen las URLs de las webs de los autores de comentarios y los metadatos de los perfiles de usuario.


#Cambiar el dominio de WordPress con WP-CLI search-replace

La interfaz de línea de comandos de WordPress (WP-CLI) es la herramienta más rápida, fiable y automatizable para migrar URLs. Trabaja directamente en el servidor a través de SSH y opera sobre las estructuras de PHP en memoria.

#Paso 1: copia de seguridad

Antes de tocar la base de datos de producción, vuélcala a un archivo SQL:

# Volcado de la base de datos con sentencias DROP TABLE
wp db export copia-antes-de-migrar-$(date +%Y%m%d_%H%M%S).sql --add-drop-table

Si la base de datos se daña, recuperarás el estado original en segundos:

wp db import copia-antes-de-migrar-*.sql

#Paso 2: prueba en seco con —dry-run

La opción --dry-run muestra cuántas filas y en qué tablas se modificarían, sin cambiar nada en la base de datos:

wp search-replace 'https://dominio-antiguo.es' 'https://dominio-nuevo.es' --all-tables --dry-run

El resultado es una tabla con las columnas Table, Column, Replacements y Type, más una línea de resumen con el total de sustituciones. La columna Type indica si esa columna se procesó en SQL o en PHP. Si el número de sustituciones es cero, lo más habitual es que la URL antigua no coincida con la guardada en la base de datos por el protocolo, por el prefijo www o por una barra final.

#Paso 3: sustitución real en producción

Para la sustitución definitiva recomendamos este conjunto de opciones:

wp search-replace 'https://dominio-antiguo.es' 'https://dominio-nuevo.es' \
  --all-tables \
  --precise \
  --recurse-objects \
  --skip-columns=guid \
  --report-changed-only

Qué hace cada opción:

  • --all-tables: recorre todas las tablas de la base de datos, incluidas las tablas propias de plugins de comercio electrónico, formularios y registros.
  • --precise: fuerza el uso de PHP en lugar de SQL en todas las columnas. La documentación de WP-CLI lo describe como más lento pero más fiable con datos serializados complejos.
  • --recurse-objects: entra de forma recursiva en los objetos serializados. Está activada por defecto y se desactiva con --no-recurse-objects, así que escribirla solo deja clara la intención.
  • --skip-columns=guid: omite la columna guid de wp_posts y evita que los lectores RSS dupliquen entradas.
  • --report-changed-only: muestra en el resumen solo las tablas en las que hubo cambios y oculta cientos de filas vacías.

Si necesitas una búsqueda sin distinguir mayúsculas, --regex por sí sola no basta: hay que añadir --regex-flags='i', y la documentación advierte que el modo regex es mucho más lento.

#Cambiar el dominio en una red WordPress Multisite

En las instalaciones Multisite (una red de varios sitios) las tablas tienen prefijos propios (por ejemplo wp_2_posts, wp_3_options) y los dominios de cada subsitio se guardan en las tablas wp_blogs y wp_site.

En ese entorno se usa la opción --network, que abarca todas las tablas registradas en $wpdb para toda la red, o --all-tables-with-prefix, que añade las tablas con el prefijo que no están registradas en $wpdb:

wp search-replace 'https://red-antigua.es' 'https://red-nueva.es' --network --all-tables-with-prefix

La documentación de WordPress reconoce que, al cambiar el dominio de una red Multisite, este paso “todavía no se puede automatizar fácilmente” (Migrating WordPress, developer.wordpress.org, traducción propia). Después de la sustitución revisa a mano:

  • las tablas wp_site y wp_blogs, donde están el dominio y la ruta de la red y de cada subsitio,
  • las opciones home, siteurl y fileupload_url en la tabla de opciones de cada sitio (wp_options, wp_2_options y siguientes),
  • al pasar de subdominios a subdirectorios o al revés: el archivo .htaccess y la constante SUBDOMAIN_INSTALL de wp-config.php.

#Cómo exportar la base de datos con las nuevas URLs a un archivo SQL

Si preparas una migración de base de datos para un cliente en tu entorno local y quieres generar un archivo SQL con los dominios ya sustituidos sin tocar tu base de datos de trabajo:

wp search-replace 'https://localhost/proyecto' 'https://dominio-cliente.es' \
  --all-tables \
  --export=base-lista-para-importar.sql

#Pasar de www al dominio sin www

Cuando solo cambia el prefijo, sustituye la dirección completa con su protocolo, para no tocar cadenas ajenas que contengan el mismo nombre:

wp search-replace 'https://www.sudominio.es' 'https://sudominio.es' --all-tables --precise --skip-columns=guid --dry-run

#Cambiar las URLs con el plugin Better Search Replace

Si gestionas el sitio en un hosting compartido sin acceso SSH o prefieres trabajar desde el escritorio de WordPress, la opción más segura es el plugin Better Search Replace, mantenido por el equipo de WP Engine (antes Delicious Brains).

Paso a paso en el escritorio de WordPress:
1. Vaya a Plugins > Añadir plugin y busque "Better Search Replace".
2. Instale y active el plugin.
3. Vaya a Herramientas > Better Search Replace.
4. En el campo "Search for" escriba la URL antigua (por ejemplo https://dominio-antiguo.es).
5. En el campo "Replace with" escriba la URL nueva (por ejemplo https://dominio-nuevo.es).
6. Seleccione todas las tablas de la lista (Ctrl+A en Windows o Cmd+A en macOS).
7. Compruebe que la opción "Run as dry run?" está MARCADA.
8. Pulse "Run Search/Replace" y analice el informe.
9. Desmarque "Run as dry run?" y repita el proceso para guardar los cambios.

#Errores de Better Search Replace y cómo solucionarlos

  • Error 504 Gateway Timeout o límite de tiempo de ejecución superado (max_execution_time): Con bases de datos grandes el servidor web puede cortar la petición HTTP. En la pestaña Settings del plugin reduce el parámetro Max Page Size. El valor por defecto es de 20000 filas por lote, como se ve en el código fuente del plugin (class-bsr-admin.php); un lote más pequeño significa más peticiones, pero más cortas.

#Cómo cambiar siteurl y home en WordPress

Dos opciones de la tabla wp_options deciden si podrás siquiera iniciar sesión en el sitio con la nueva dirección. La documentación de WordPress (Changing The Site URL) las distingue así: home es la “Dirección del sitio (URL)”, la dirección que los visitantes escriben en el navegador, y siteurl es la “Dirección de WordPress (URL)”, el lugar donde están los archivos del núcleo. Ambos campos de Ajustes > Generales deben incluir https:// y no deben terminar en barra.

La documentación describe varias formas de cambiar estos valores. Cada una sirve para una situación distinta:

MétodoCuándo usarloPrecauciones
wp option update en WP-CLITienes SSH y el escritorio no funcionaSolo cambia dos opciones, el resto de URLs las corrige wp search-replace
Constantes WP_HOME y WP_SITEURL en wp-config.phpHay que levantar el sitio rápidoLos valores quedan fijados en el código y los campos de Ajustes > Generales no se pueden editar
update_option() en el functions.php del temaSolo tienes acceso FTPHay que borrar el código en cuanto cargue el escritorio
Constante RELOCATEEl sitio se ha movido a otro directorio u otro servidorSolo corrige las direcciones del panel y dejarla en el archivo es inseguro
Edición de wp_options en phpMyAdminSolo tienes el panel del hostingPrimero una copia de la base de datos; el prefijo puede no ser wp_

#Cambiar siteurl y home con WP-CLI

La documentación propone dos comandos y, después, la sustitución de URLs en el contenido sin tocar la columna guid:

wp option update home 'https://dominio-nuevo.es'
wp option update siteurl 'https://dominio-nuevo.es'
wp search-replace 'https://dominio-antiguo.es' 'https://dominio-nuevo.es' --skip-columns=guid

#Cambiar la dirección desde functions.php

Si solo tienes acceso por FTP, la documentación indica añadir al archivo functions.php del tema activo, justo después de la etiqueta de apertura <?php, dos líneas:

update_option( 'siteurl', 'https://dominio-nuevo.es' );
update_option( 'home', 'https://dominio-nuevo.es' );

Tras subir el archivo, abre varias veces la pantalla de acceso o el escritorio y después borra esas líneas. La documentación es tajante: “No deje este código en el archivo functions.php” (Migrating WordPress, developer.wordpress.org, traducción propia). El código se ejecutaría en cada petición y sobrescribiría las opciones que más adelante quieras cambiar desde el escritorio.

#La constante RELOCATE tras mover el directorio

La constante define( 'RELOCATE', true );, añadida en wp-config.php antes del comentario That's all, stop editing!, hace que WordPress adopte la dirección actual cuando inicias sesión mediante wp-login.php en el nuevo servidor. Según la documentación solo corrige las direcciones del panel, no el resto de la configuración, y dejarla puesta es inseguro: “Elimine siempre la línea RELOCATE de wp-config.php cuando termine” (Migrating WordPress, developer.wordpress.org, traducción propia).

#Transients en la base de datos migrada

La documentación llama la atención sobre los transients, valores temporales guardados en wp_options. Pueden contener URLs antiguas y, como WordPress los vuelve a generar por sí mismo, se pueden borrar sin riesgo en la copia migrada de la base de datos. Con WP-CLI lo hace wp transient delete --all, y la documentación da también una consulta para phpMyAdmin, siempre con una copia previa:

DELETE FROM `wp_options` WHERE `option_name` LIKE '%\_transient\_%';

#Cómo cambiar las URLs cuando el escritorio de WordPress no funciona

En una emergencia, sin acceso SSH y con el escritorio de WordPress caído por un bucle de redirecciones o por archivos dañados, la herramienta probada desde hace más de una década sigue siendo el script Search-Replace-DB (conocido como SRDB) de la agencia Interconnect/it.

Cómo usar el script SRDB:
1. Descargue el archivo zip oficial desde interconnectit.com.
2. Descomprima los archivos y cambie el nombre de la carpeta por una cadena única y difícil de adivinar (por ejemplo srdb-sec-8f7a9d/).
3. Suba la carpeta al servidor por FTP o SFTP al directorio principal de WordPress (donde está wp-config.php).
4. Abra en el navegador https://su-dominio.es/srdb-sec-8f7a9d/.
5. El script lee automáticamente los datos de acceso a la base de datos de wp-config.php.
6. Rellene los campos "replace" (valor antiguo) y "with" (valor nuevo).
7. Pulse "dry run" y, tras comprobarlo, "live run".
8. CRÍTICO: al terminar, pulse el botón rojo "delete me" para que el script se borre del servidor.

[!CAUTION] Dejar el script Search-Replace-DB en un servidor en funcionamiento es un agujero de seguridad crítico. Cualquiera que adivine la ruta del script obtiene acceso completo de lectura y escritura a la base de datos sin necesidad de contraseña. Compruebe siempre que la carpeta se ha borrado al terminar.


#Cambiar las URLs en Elementor, Divi y Gutenberg

Los constructores de páginas y el editor de bloques Gutenberg añaden capas extra de codificación de datos que hay que tener en cuenta al actualizar las URLs.

graph LR
    subgraph WP_CLI_Execution["Paso 1: base de datos"]
        A["wp search-replace"] --> B["Tablas wp_posts, wp_postmeta, wp_options"]
    end
    
    subgraph Builder_Sync["Paso 2: constructores de páginas"]
        B --> C["Elementor: Tools > Replace URL"]
        B --> D["Elementor: regenerar archivos CSS"]
    end
    
    subgraph Edge_Purge["Paso 3: caché y borde"]
        C & D --> F["wp cache flush (Redis/Memcached)"]
        F --> G["Purgar la CDN (Cloudflare)"]
    end

#1. URLs en los datos JSON de Elementor

Elementor guarda el diseño de las páginas en el campo meta _elementor_data en formato JSON, donde las barras de las URLs suelen ir precedidas de un carácter de escape (escaped slashes):

{\"url\":\"https:\/\/dominio-antiguo.es\/wp-content\/uploads\/2026\/08\/banner.jpg\"}

Una búsqueda normal de https://dominio-antiguo.es puede no coincidir con la cadena escapada https:\/\/dominio-antiguo.es. Además, Elementor compila los estilos en archivos CSS estáticos dentro de wp-content/uploads/elementor/css/.

Procedimiento correcto tras migrar un sitio hecho con Elementor:

  1. Ejecuta el wp search-replace habitual en la base de datos.
  2. Entra en el escritorio de WordPress y ve a Elementor > Tools > Replace URL.
  3. Escribe la URL antigua y la nueva y pulsa Replace URL.
  4. En la pestaña General pulsa el botón Regenerate Files & Data.

#2. URLs en los bloques de Gutenberg

Los bloques de Gutenberg guardan los atributos de los medios directamente en comentarios HTML dentro de post_content:

<!-- wp:image {"id":412,"sizeSlug":"full","linkDestination":"custom"} -->
<figure class="wp-block-image size-full"><a href="https://dominio-antiguo.es/oferta/"><img src="https://dominio-antiguo.es/wp-content/uploads/2026/08/imagen.png" alt="Oferta"/></a></figure>
<!-- /wp:image -->

Tanto wp search-replace como Better Search Replace lo resuelven sin problema, siempre que recorran la columna post_content de la tabla wp_posts.

#3. URLs escritas directamente en los archivos del tema

Algunos temas y plugins llevan direcciones escritas directamente en archivos PHP, CSS o JavaScript. Ninguna sustitución en la base de datos las alcanza, pero es fácil encontrarlas en el servidor:

grep -rn "dominio-antiguo.es" wp-content/themes/su-tema/

#Cambiar el dominio de una tienda WooCommerce

Al cambiar el dominio de una tienda basada en WooCommerce hay que prestar especial atención a los módulos que se comunican con pasarelas de pago, transportistas y sistemas ERP:

  1. Pasarelas de pago:
    • La mayoría de las pasarelas registran en su panel de desarrollador las direcciones de notificación de vuelta (webhooks o IPN). Si cambias el dominio, las notificaciones de pedidos pagados seguirán llegando a la dirección antigua y provocarán errores en las transacciones.
    • Después de wp search-replace, entra en el panel de cada proveedor de pagos y actualiza la dirección del webhook para que apunte al dominio nuevo.
  2. Claves y webhooks de la API REST de WooCommerce:
    • En WooCommerce > Settings > Advanced > Webhooks comprueba que las direcciones de destino (Delivery URL) se han actualizado. Si los webhooks sincronizan el stock con un ERP, actualiza también las direcciones de los endpoints en el software de integración.
  3. Sesiones y carritos de los clientes:
    • La tabla wp_woocommerce_sessions guarda datos temporales de los carritos. Tras el cambio de dominio conviene vaciar las sesiones en WooCommerce > Status > Tools > Clear customer sessions para evitar errores de tokens de sesión al cambiar las cookies del dominio.

#Search-replace en una base de datos grande y en clústeres MySQL

Con bases de datos muy grandes, una sola pasada de wp search-replace por todas las tablas tarda mucho y durante todo ese tiempo escribe en tablas que el sitio en funcionamiento está usando. La documentación de WP-CLI menciona dos limitaciones que conviene conocer: las tablas sin clave primaria se omiten, y las opciones --regex y --log ralentizan el trabajo de forma notable.

#1. Cómo dividir search-replace en partes más pequeñas

El comando wp search-replace no tiene opciones --batch-size ni --limit; la lista de opciones de la documentación de WP-CLI no las incluye y las instrucciones que las mencionan no funcionarán. El trabajo se divide de otra manera: indicando los nombres de las tablas como argumentos (se admiten comodines) o excluyendo tablas con --skip-tables:

# Primero el contenido, después los metadatos, en pasadas separadas
wp search-replace 'https://antiguo.es' 'https://nuevo.es' wp_posts --precise --skip-columns=guid
wp search-replace 'https://antiguo.es' 'https://nuevo.es' wp_postmeta --precise

# Todo salvo una tabla grande de registros de un plugin
wp search-replace 'https://antiguo.es' 'https://nuevo.es' --all-tables --skip-tables='wp_*_log' --precise --skip-columns=guid

La opción --include-columns limita la sustitución a las columnas indicadas, y con --export el número de filas por sentencia INSERT lo fija --export_insert_size (50 por defecto).

#2. Search-replace con replicación (Amazon Aurora, MySQL Galera)

Si la base de datos funciona con una arquitectura maestro-réplica o en un clúster Galera, modificar millones de registros de golpe genera un gran volumen de datos en el registro binario (binlog). Eso puede provocar un retraso de replicación considerable en los nodos de lectura.

Estrategia recomendada para entornos de alta disponibilidad:

  • Hacer la operación en una ventana de mantenimiento con el menor tráfico posible.
  • Desconectar temporalmente los nodos de réplica mientras dura la escritura masiva.
  • Usar la opción --export para preparar el archivo SQL procesado en una máquina de trabajo aparte e importarlo durante la ventana de mantenimiento.

#3. Modo de mantenimiento durante la migración

WP-CLI puede activar el modo de mantenimiento de WordPress, de modo que los visitantes no vean el sitio a medio pasar a la nueva dirección:

wp maintenance-mode activate
wp search-replace 'https://antiguo.es' 'https://nuevo.es' --all-tables --precise --skip-columns=guid
wp maintenance-mode deactivate

#Pasar de HTTP a HTTPS y configurar el servidor web

Si el objetivo de la migración no es cambiar el dominio sino instalar un certificado SSL y pasar del protocolo sin cifrar al cifrado:

wp search-replace 'http://sudominio.es' 'https://sudominio.es' \
  --all-tables \
  --precise \
  --skip-columns=guid

Así eliminas el problema del Mixed Content (contenido mixto), en el que el navegador bloquea scripts, fuentes o imágenes servidos por el antiguo protocolo http://. Limita siempre la sustitución a tu propio dominio: un reemplazo de http:// a secas cambiaría también los enlaces a sitios externos.

#Redirecciones 301 en Nginx y Apache

Tras cambiar el dominio en la base de datos, el paso crítico para el SEO es redirigir todo el tráfico de la dirección antigua a la nueva con el código de estado HTTP 301 (Moved Permanently).

Configuración de Nginx (/etc/nginx/sites-available/dominio-antiguo.conf):

server {
    listen 80;
    listen 443 ssl http2;
    server_name dominio-antiguo.es www.dominio-antiguo.es;

    ssl_certificate /etc/letsencrypt/live/dominio-antiguo.es/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/dominio-antiguo.es/privkey.pem;

    return 301 https://dominio-nuevo.es$request_uri;
}

Configuración de Apache (.htaccess en el servidor antiguo):

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^(?:www\.)?dominio-antiguo\.es$ [NC]
    RewriteRule ^(.*)$ https://dominio-nuevo.es/$1 [L,R=301]
</IfModule>

#Constantes de wp-config.php frente a los valores de la base de datos

Una práctica habitual durante una avería es forzar las URLs en el archivo wp-config.php:

define('WP_HOME', 'https://dominio-nuevo.es');
define('WP_SITEURL', 'https://dominio-nuevo.es');

Conviene saber cómo funcionan estas constantes:

  • Las constantes definidas en wp-config.php sustituyen los valores de siteurl y home que lee WordPress, pero no cambian los registros de la base de datos. La documentación lo llama directamente fijar los valores en el código y advierte que no es necesariamente la mejor solución.
  • Los campos de dirección de Ajustes > Generales dejan de poder editarse.
  • Los enlaces del contenido de las entradas, los adjuntos y los widgets seguirán apuntando a la dirección antigua.
  • Trata las constantes de wp-config.php como una solución temporal; al final la base de datos siempre debe actualizarse con wp search-replace.

#Checklist para cambiar el dominio de WordPress

Antes de empezar conviene seguir un plan ordenado:

FaseTareaHerramienta o comando
Antes de migrarVolcado completo de la base de datoswp db export backup-$(date +%s).sql --add-drop-table
Antes de migrarCopia de wp-content/uploads y .htaccessrsync / tar -czf uploads.tar.gz
Antes de migrarDesactivar plugins de caché y minificaciónEscritorio / wp plugin deactivate
DurantePrueba en seco de la sustituciónwp search-replace 'old' 'new' --all-tables --dry-run
DuranteSustitución real en la base de datoswp search-replace 'old' 'new' --all-tables --precise --skip-columns=guid
DuranteCambio de dominio en constructores (Elementor)Escritorio > Elementor > Tools > Replace URL
Después de migrarVaciar la caché de objetos y los transientswp cache flush y wp transient delete --all
Después de migrarRegenerar los enlaces permanenteswp rewrite flush --hard

#Script Bash para sincronizar la base de datos de WordPress entre entornos

En flujos de trabajo con contenedores Docker o entornos de desarrollo y staging (DDEV, Lando, LocalWP), escribir los comandos a mano cada vez lleva tiempo y da pie a errores. Lo habitual en los equipos técnicos es preparar un script de Bash que descargue la base de datos de producción, la importe en local y sustituya los dominios.

#!/usr/bin/env bash
# Script de sincronización automática de la base de datos: sync-db.sh
set -eo pipefail

PROD_HOST="su-servidor-de-produccion.es"
PROD_USER="deploy"
PROD_PATH="/var/www/html"
PROD_URL="https://suempresa.es"
LOCAL_URL="https://proyecto.local"
BACKUP_DIR="./backups"

mkdir -p "${BACKUP_DIR}"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
DUMP_FILE="${BACKUP_DIR}/dump_prod_${TIMESTAMP}.sql"

echo "==> 1/4 Descargando la base de datos de producción por SSH..."
ssh "${PROD_USER}@${PROD_HOST}" "cd ${PROD_PATH} && wp db export - --add-drop-table" > "${DUMP_FILE}"

echo "==> 2/4 Importando la base de datos en el entorno local..."
wp db import "${DUMP_FILE}"

echo "==> 3/4 Sustituyendo dominios respetando la serialización..."
wp search-replace "${PROD_URL}" "${LOCAL_URL}" \
  --all-tables \
  --precise \
  --recurse-objects \
  --skip-columns=guid \
  --report-changed-only

echo "==> 4/4 Vaciando cachés y regenerando enlaces..."
wp cache flush
wp rewrite flush --hard

echo "==> Listo. El entorno local está sincronizado en ${LOCAL_URL}."

#Comprobar la serialización al terminar

Si quieres asegurarte de que ningún campo de la base de datos se ha dañado durante la migración, puedes ejecutar un breve script PHP con WP-CLI que comprueba la integridad de todos los registros serializados de la tabla wp_options:

wp eval '
global $wpdb;
$options = $wpdb->get_results("SELECT option_name, option_value FROM {$wpdb->options} WHERE option_value LIKE \"a:%\" OR option_value LIKE \"O:%\"");
$broken = 0;
foreach ($options as $opt) {
    if (is_serialized($opt->option_value) && @unserialize($opt->option_value) === false) {
        echo "Opción dañada: " . $opt->option_name . PHP_EOL;
        $broken++;
    }
}
if ($broken === 0) {
    echo "Todas las opciones serializadas de wp_options son correctas." . PHP_EOL;
} else {
    echo "Se han encontrado " . $broken . " registros dañados." . PHP_EOL;
}
'

#Errores después de cambiar el dominio de WordPress y cómo solucionarlos

#1. Bucle de redirecciones tras cambiar el dominio (ERR_TOO_MANY_REDIRECTS)

Si después del cambio el sitio entra en un bucle de redirecciones infinito:

  • Comprueba que siteurl y home en wp_options tienen exactamente el mismo protocolo (https://) y el mismo prefijo (con o sin www) que los configurados en el servidor web o en Cloudflare.
  • Revisa la configuración SSL de Cloudflare (el modo SSL/TLS debe estar en Full (Strict), no en Flexible).
  • Restablece el archivo .htaccess a la versión por defecto de WordPress con:
    wp rewrite flush --hard

#2. Desaparecen los estilos CSS y los iconos tras la migración

  • Si la página carga como texto sin estilos, la causa más habitual son hojas de estilo y scripts que siguen apuntando a la dirección antigua, el contenido mixto (Mixed Content) al pasar a HTTPS o el bloqueo de recursos por la política CORS.
  • Abre la consola de desarrollo del navegador (tecla F12, pestaña Console) para localizar los archivos que se cargan desde la antigua dirección http://.

#3. Widgets o campos de ACF dañados

  • Si se ignoraron las reglas de la serialización y se ejecutó un REPLACE de SQL a pelo, la única salida segura es restaurar la base de datos desde el volcado previo (wp db import backup.sql) y repetir la operación con wp search-replace --precise.

#4. Error Allowed memory size exhausted en WP-CLI

Al ejecutar search-replace sobre tablas con enormes cantidades de texto (por ejemplo, tablas de registros o revisiones de entradas muy grandes), el proceso PHP de la terminal puede agotar el límite de memoria asignado:

  • Para aumentar temporalmente la memoria de un solo comando de WP-CLI, ejecútalo con la opción de PHP correspondiente:
    php -d memory_limit=1024M /usr/local/bin/wp search-replace 'https://antiguo.es' 'https://nuevo.es' --all-tables
  • También conviene borrar antes de la migración las revisiones innecesarias y los transients caducados:
    wp transient delete --all && wp post delete $(wp post list --post_type='revision' --format=ids) --force

#5. Incompatibilidad de codificación y de collation

Al mover un volcado a un servidor de base de datos más antiguo o distinto, puede ocurrir que el servidor de destino no conozca la collation usada en el volcado, por ejemplo utf8mb4_unicode_520_ci:

  • Si al importar el archivo .sql aparece el error #1273 - Unknown collation: 'utf8mb4_unicode_520_ci', sustituye esa cadena en el archivo SQL antes de importarlo:
    sed -i 's/utf8mb4_unicode_520_ci/utf8mb4_unicode_ci/g' backup.sql
  • Ambas collations usan utf8mb4, así que las tildes y la eñe se conservan; solo cambia la regla de ordenación y comparación de texto.

#Resumen

Actualizar correctamente las URLs en la base de datos de WordPress exige entender cómo funcionan PHP y las bases de datos relacionales. Las consultas SQL a pelo o la edición del volcado en un editor de texto son el camino más corto para desestabilizar el sitio y perder la configuración.

WP-CLI con las opciones --all-tables --precise --skip-columns=guid, precedido de una copia de seguridad y de una pasada --dry-run, conserva intactos los datos serializados y la columna guid.

¿Preparas una modernización completa del sitio, un cambio a arquitectura headless o una migración a plataformas de nueva generación? Consulta nuestros servicios de desarrollo WordPress, de migración de WordPress a Astro y Next.js y la auditoría de Core Web Vitals. Antes del corte DNS en producción, reserva una evaluación de migración WordPress para encontrar huecos de redirección y URLs serializadas sin tocar live.

Siguiente paso

Transforma el artículo en una implementación real

Este bloque refuerza el enlazado interno y lleva al lector al siguiente paso más útil dentro de la arquitectura del sitio.

¿Quieres implementar esto en tu sitio?

Si quieres transformar el artículo en mejoras concretas, rediseño o un plan de implementación, puedo cerrar el alcance y ejecutar.

Cluster relacionado

Explora otros servicios WordPress y base de conocimiento

Refuerza tu negocio con soporte técnico profesional en áreas clave del ecosistema WordPress.

Preguntas frecuentes

Respuestas prácticas para aplicar el tema en la ejecución real.

Por qué un UPDATE de SQL con REPLACE rompe la base de datos de WordPress#
WordPress guarda configuraciones complejas, widgets, ajustes del tema y campos de ACF como arrays PHP serializados (por ejemplo s:15:"https://old.com"). La función REPLACE de SQL cambia el texto pero no actualiza el contador de caracteres. Al leerlo, PHP detecta que la longitud no coincide y descarta toda la estructura como dañada.
Cuál es la herramienta más segura para cambiar el dominio en la base de datos de WordPress#
La herramienta más recomendada es el WP-CLI oficial con el comando wp search-replace. Según la documentación de WP-CLI, el comando maneja correctamente los datos serializados de PHP: los deserializa, sustituye el texto, recalcula las longitudes y los vuelve a guardar.
Hay que cambiar las URLs de la columna guid de la tabla wp_posts#
No. La columna guid es el identificador único y permanente de cada entrada que usan los lectores de feeds. La documentación de WordPress indica que nunca debe cambiarse, por eso en WP-CLI se usa la opción --skip-columns=guid.
Cómo actualizar las URLs en un hosting compartido sin acceso SSH#
Sin acceso SSH, la documentación de WordPress señala el plugin Better Search Replace (mantenido por WP Engine) o el script Search and Replace for WordPress Databases de Interconnect/it. El script debe borrarse del servidor en cuanto termine el trabajo.
Qué hacer si los widgets desaparecen después de la migración#
Si los widgets desaparecen, los datos serializados se han dañado. Restaura la copia de seguridad con 'wp db import backup.sql' y repite la migración con una herramienta que respete la serialización, como WP-CLI o Better Search Replace.

¿Necesitas un FAQ adaptado a tu sector y mercado? Preparamos una versión alineada con tus objetivos de negocio.

Hablemos

Artículos Relacionados

Benchmarks de hosting WordPress 2026

Las pruebas comparativas Review Signal de Kevin Ohashi regresaron en 2026 tras tres años de pausa, impulsados por una plataforma de pruebas de carga de código abierto totalmente nueva. Desglosamos los cinco niveles de precio más WooCommerce, nombramos a los ganadores, nombramos a los hostings que se quedaron fuera y traducimos los datos para agencias europeas.