Como atualizar URLs na base de dados WordPress ao mudar de domínio

Como atualizar URLs na base de dados WordPress ao mudar de domínio

Última verificação: 14 de outubro de 2026
26 min de leitura
Tutorial
Arquitetura de servidores

Mover um site WordPress do ambiente de desenvolvimento para o domínio de produção, mudar o nome da marca ou instalar um certificado SSL (passar de HTTP para HTTPS) são tarefas de rotina para qualquer administrador ou programador. À primeira vista parece simples: exporta-se a base de dados para um ficheiro .sql, abre-se num editor de código, usa-se a função “Localizar e substituir” e volta-se a importar o ficheiro. Ou corre-se uma consulta SQL rápida no phpMyAdmin.

Fazer isto numa base de dados WordPress de produção deita o site abaixo de imediato. Os widgets do rodapé e das barras laterais desaparecem, as cores e a tipografia do tema voltam ao padrão, os campos avançados (ACF) devolvem valores vazios e as configurações dos plugins de comércio eletrónico ficam a zero.

A causa está na forma como o WordPress e os plugins guardam estruturas de dados complexas na base de dados relacional MySQL ou MariaDB. A documentação do WordPress avisa sem rodeios: uma pesquisa e substituição simples em toda a base de dados pode estragar a serialização, porque alguns temas e widgets guardam o endereço juntamente com o seu comprimento (Migrating WordPress, developer.wordpress.org). Perceber a serialização do PHP e dominar as ferramentas certas, sobretudo a interface de linha de comandos WP-CLI, é a base para gerir sites WordPress com segurança.


#O que são dados serializados na base de dados WordPress

As bases de dados SQL relacionais foram desenhadas para guardar dados escalares: números, cadeias de texto curtas ou datas. O WordPress, no entanto, precisa muitas vezes de guardar numa única linha de uma tabela uma estrutura complexa e multidimensional, por exemplo um array com a lista de widgets ativos, a sua ordem, os ícones atribuídos e os parâmetros de configuração.

Em vez de criar dezenas de tabelas normalizadas adicionais para cada plugin, os criadores do WordPress optaram por uma função nativa do PHP: serialize().

// Exemplo de array de configuração de um tema em PHP
$theme_settings = array(
    'site_name'    => 'A Minha Loja WordPress',
    'logo_url'     => 'https://dominio-antigo.pt/logo.png',
    'contact_mail' => '[email protected]'
);

// Resultado de serialize($theme_settings)
// Guardado diretamente na coluna option_value da tabela wp_options:
a:3:{s:9:"site_name";s:22:"A Minha Loja WordPress";s:8:"logo_url";s:34:"https://dominio-antigo.pt/logo.png";s:12:"contact_mail";s:23:"[email protected]";}

#Como ler uma string serializada

Vejamos com mais atenção o fragmento que representa o URL do logótipo:

s:34:"https://dominio-antigo.pt/logo.png";

Cada elemento no formato serializado do PHP tem uma estrutura rígida:

  • s indica o tipo de dados: string (cadeia de caracteres).
  • 34 é o comprimento declarado da string (o número exato de bytes).
  • "https://dominio-antigo.pt/logo.png" é o valor propriamente dito, entre aspas.

A peça-chave é o número 34. Ao ler os dados da base de dados, o PHP chama a função unserialize(). O analisador do PHP não procura a aspa de fecho às cegas: conta exatamente 34 bytes a partir da posição indicada.

#Porque é que o SQL REPLACE estraga os dados serializados

Suponha a migração do site para um domínio novo e mais longo: https://dominio-novo-muito-mais-longo-da-empresa.pt. O novo endereço do logótipo é https://dominio-novo-muito-mais-longo-da-empresa.pt/logo.png, com 60 caracteres.

Se executar a consulta SQL tradicional:

-- ERRO CRÍTICO: esta consulta destrói a serialização!
UPDATE wp_options
SET option_value = REPLACE(option_value, 'https://dominio-antigo.pt', 'https://dominio-novo-muito-mais-longo-da-empresa.pt');

Na base de dados fica esta string:

s:34:"https://dominio-novo-muito-mais-longo-da-empresa.pt/logo.png";

O que acontece quando um visitante abre o site:

  1. O WordPress lê a linha da base de dados e passa-a à função unserialize().
  2. A função lê o cabeçalho s:34 e espera exatamente 34 caracteres.
  3. O PHP corta os primeiros 34 caracteres do novo endereço (https://dominio-novo-muito-mais-lo) e, em vez da aspa de fecho e do ponto e vírgula obrigatórios, encontra letras soltas.
  4. O analisador do PHP emite o erro PHP Notice: unserialize(): Error at offset... e devolve false.
  5. O tema ou o plugin recebe false em vez do array de opções esperado.
  6. O WordPress assume que os dados não existem e repõe as definições de fábrica do tema ou remove os widgets.

#Onde é que o WordPress guarda os URLs na base de dados

Os URLs de uma instalação WordPress não estão num só sítio. Estão espalhados por várias tabelas do sistema e por tabelas criadas por módulos externos:

graph TD
    A["Base de dados WordPress"] --> B["wp_options"]
    A --> C["wp_posts"]
    A --> D["wp_postmeta"]
    A --> E["wp_comments / wp_commentmeta"]
    A --> F["wp_usermeta"]
    A --> G["Tabelas de plugins (WooCommerce, formulários, SEO)"]

    B --> B1["siteurl e home (endereços principais)"]
    B --> B2["sidebars_widgets (serializado)"]
    B --> B3["theme_mods (serializado)"]

    C --> C1["post_content (links, imagens)"]
    C --> C2["post_excerpt"]
    C --> C3["guid (NÃO alterar em artigos publicados!)"]

    D --> D1["_elementor_data (JSON escapado)"]
    D --> D2["_wp_attached_file (caminhos de multimédia)"]
    D --> D3["Campos ACF (serializados)"]

#1. Tabela wp_options

É a tabela de configuração mais importante. Contém dois registos críticos para o funcionamento do site:

  • siteurl: indica onde estão fisicamente os ficheiros do WordPress (o caminho do núcleo).
  • home: indica o endereço principal do site que os utilizadores escrevem no browser.

Além destes, a tabela guarda em forma serializada:

  • sidebars_widgets: a disposição dos widgets nas barras laterais e nos rodapés.
  • theme_mods_[nome_do_tema]: cores, disposição do cabeçalho, tipografia e logótipo definidos no personalizador de temas (Customizer).
  • Definições de plugins de SEO (Rank Math, Yoast), de segurança e de cache.

#2. Tabela wp_posts

Guarda o conteúdo de artigos, páginas, produtos WooCommerce e elementos da biblioteca multimédia.

  • Coluna post_content: contém ligações absolutas para outras páginas, etiquetas <img> incorporadas, ligações para ficheiros PDF e comentários de blocos do Gutenberg.
  • Coluna guid (Globally Unique Identifier): o identificador único do artigo. Regra importante: a documentação do WordPress diz: “Nunca, mas nunca, altere o conteúdo da coluna GUID, em circunstância alguma” (Migrating WordPress, developer.wordpress.org, tradução própria). A coluna guid não deve ser alterada porque os leitores de feeds RSS a usam para detetar artigos novos. Se o guid mudar, os leitores de RSS tratam todos os artigos antigos como novos e enviam notificações repetidas aos subscritores.

#3. Tabela wp_postmeta

Contém os atributos adicionais de artigos e páginas. É aqui que ficam os arrays serializados dos campos personalizados do plugin Advanced Custom Fields (ACF), os metadados dos anexos (_wp_attachment_metadata) e as configurações de construtores de páginas como o Elementor ou o Divi.

#4. Tabelas wp_usermeta e wp_comments

Contêm os URLs dos sites pessoais dos autores de comentários e os metadados dos perfis de utilizador.


#Mudar o domínio WordPress com o WP-CLI search-replace

A interface de linha de comandos do WordPress (WP-CLI) é a ferramenta mais rápida, fiável e automatizável para migrar URLs. Corre diretamente no servidor através de uma ligação SSH e trabalha com as estruturas de objetos PHP em memória.

#Passo 1: fazer a cópia de segurança

Antes de qualquer operação na base de dados de produção, exporte-a para um ficheiro SQL:

# Exportação da base de dados com instruções DROP TABLE
wp db export backup-antes-migracao-$(date +%Y%m%d_%H%M%S).sql --add-drop-table

Se a base de dados ficar danificada, repõe o estado original em segundos:

wp db import backup-antes-migracao-*.sql

#Passo 2: executar um teste sem gravar (—dry-run)

A flag --dry-run mostra quantas linhas e em que tabelas seriam alteradas, sem mudar nada na base de dados:

wp search-replace 'https://dominio-antigo.pt' 'https://dominio-novo.pt' --all-tables --dry-run

O resultado é uma tabela com as colunas Table, Column, Replacements e Type, seguida de uma linha de resumo com o total de substituições. A coluna Type mostra se cada coluna foi processada em SQL ou em PHP. Se o número de substituições for zero, o mais habitual é o endereço antigo diferir do que está na base de dados no protocolo, no prefixo www ou na barra final.

#Passo 3: executar a substituição real em produção

Para a substituição definitiva, recomendamos este conjunto de flags:

wp search-replace 'https://dominio-antigo.pt' 'https://dominio-novo.pt' \
  --all-tables \
  --precise \
  --recurse-objects \
  --skip-columns=guid \
  --report-changed-only

O que faz cada parâmetro:

  • --all-tables: percorre todas as tabelas da base de dados, incluindo as tabelas próprias de plugins de comércio eletrónico, formulários e registos.
  • --precise: obriga a usar PHP em vez de SQL em todas as colunas. A documentação do WP-CLI descreve-o como mais lento, mas mais fiável com dados serializados complexos.
  • --recurse-objects: entra recursivamente nos objetos serializados. Está ativo por omissão e desliga-se com --no-recurse-objects, por isso escrevê-lo apenas documenta a intenção.
  • --skip-columns=guid: ignora a coluna guid da tabela wp_posts e protege os leitores de RSS contra artigos duplicados.
  • --report-changed-only: mostra no resumo apenas as tabelas onde houve alterações, escondendo centenas de linhas vazias.

#Mudar o domínio numa rede WordPress Multisite

Nas instalações Multisite (rede de vários sites), as tabelas do sistema têm prefixos próprios (por exemplo wp_2_posts, wp_3_options) e a informação sobre os domínios de cada subsite está nas tabelas wp_blogs e wp_site.

Neste ambiente use a flag --network, que abrange todas as tabelas registadas no $wpdb para toda a rede, ou --all-tables-with-prefix, que acrescenta as tabelas com o prefixo que não estão registadas no $wpdb:

wp search-replace 'https://rede-antiga.pt' 'https://rede-nova.pt' --network --all-tables-with-prefix

A documentação do WordPress admite que, ao mudar o domínio de uma rede Multisite, este passo “ainda não pode ser facilmente automatizado” (Migrating WordPress, developer.wordpress.org, tradução própria). Depois da substituição, confirme à mão:

  • as tabelas wp_site e wp_blogs, onde ficam o domínio e o caminho da rede e de cada subsite,
  • as opções home, siteurl e fileupload_url na tabela de opções de cada site (wp_options, wp_2_options e seguintes),
  • ao passar de subdomínios para subdiretórios ou vice-versa: o ficheiro .htaccess e a constante SUBDOMAIN_INSTALL em wp-config.php.

#Como exportar a base de dados com os novos endereços para um ficheiro SQL

Se está a preparar a migração da base de dados de um cliente num ambiente local e quer gerar um ficheiro SQL pronto, com os domínios substituídos, sem tocar na base de dados local de trabalho:

wp search-replace 'https://localhost/projeto' 'https://dominio-do-cliente.pt' \
  --all-tables \
  --export=base-pronta-para-importar.sql

#Passar de www para o domínio sem www

Quando só muda o prefixo, substitua o endereço completo com o protocolo, para não apanhar strings alheias que contenham o mesmo nome:

wp search-replace 'https://www.o-seu-dominio.pt' 'https://o-seu-dominio.pt' --all-tables --precise --skip-columns=guid --dry-run

#Mudar URLs com o plugin Better Search Replace

Se gere um site num alojamento partilhado sem acesso SSH, ou prefere trabalhar a partir do painel do WordPress, a solução mais segura é o plugin Better Search Replace, mantido pela equipa da WP Engine (antes Delicious Brains).

Passo a passo no painel do WordPress:
1. Vá a: Plugins > Adicionar plugin > pesquise "Better Search Replace".
2. Instale e ative o plugin.
3. Vá a: Ferramentas > Better Search Replace.
4. No campo "Search for", introduza o URL antigo (por exemplo https://dominio-antigo.pt).
5. No campo "Replace with", introduza o URL novo (por exemplo https://dominio-novo.pt).
6. Selecione todas as tabelas da lista (Ctrl+A no Windows ou Cmd+A no macOS).
7. Confirme que a opção "Run as dry run?" (teste sem gravar) está MARCADA.
8. Clique em "Run Search/Replace" e analise o relatório.
9. Desmarque "Run as dry run?" e repita o procedimento para gravar as alterações.

#Erros do Better Search Replace e como corrigi-los

  • Erro 504 Gateway Timeout ou limite de tempo de execução do script (max_execution_time) ultrapassado: Em bases de dados grandes, o servidor web pode interromper o pedido HTTP. No separador Settings do plugin, reduza o parâmetro Max Page Size. O valor por omissão é de 20000 linhas por lote, como se vê no código-fonte do plugin (class-bsr-admin.php); um lote menor significa mais pedidos, mas mais curtos.

#Como alterar siteurl e home no WordPress

São duas opções da tabela wp_options que decidem se consegue sequer entrar no site com o novo endereço. A documentação do WordPress (Changing The Site URL) distingue-as assim: home é o “Endereço do site (URL)”, ou seja, o endereço que os visitantes escrevem no browser, e siteurl é o “Endereço do WordPress (URL)”, o sítio onde estão os ficheiros do núcleo. Ambos os campos em Opções > Geral devem incluir https:// e não devem terminar com barra.

A documentação descreve várias formas de alterar estes valores. Cada uma serve uma situação diferente:

FormaQuando usarCuidado a ter
wp option update no WP-CLITem SSH e o painel não funcionaSó muda as duas opções; o resto dos endereços corrige-se com wp search-replace
Constantes WP_HOME e WP_SITEURL em wp-config.phpÉ preciso pôr o site a funcionar depressaOs valores ficam fixos no código e os campos em Opções > Geral deixam de ser editáveis
update_option() no functions.php do temaSó tem FTPO código tem de ser removido logo após o primeiro carregamento do painel
Constante RELOCATESite movido para outra pasta ou outro servidorSó corrige os endereços do painel e deixá-la no ficheiro é inseguro
Edição de wp_options no phpMyAdminSó tem o painel de alojamentoPrimeiro a cópia de segurança; o prefixo das tabelas pode não ser wp_

#Alterar siteurl e home com o WP-CLI

A documentação indica dois comandos, seguidos da substituição dos endereços no conteúdo, ignorando a coluna guid:

wp option update home 'https://dominio-novo.pt'
wp option update siteurl 'https://dominio-novo.pt'
wp search-replace 'https://dominio-antigo.pt' 'https://dominio-novo.pt' --skip-columns=guid

#Alterar o endereço através do functions.php

Quando só tem acesso por FTP, a documentação recomenda acrescentar ao ficheiro functions.php do tema ativo, logo a seguir à abertura <?php, duas linhas:

update_option( 'siteurl', 'https://dominio-novo.pt' );
update_option( 'home', 'https://dominio-novo.pt' );

Depois de enviar o ficheiro, abra algumas vezes o ecrã de início de sessão ou o painel e, em seguida, apague essas linhas. A documentação é clara: “Não deixe este código no ficheiro functions.php” (Migrating WordPress, developer.wordpress.org, tradução própria). O código correria em cada pedido e sobrescreveria opções que mais tarde queira mudar a partir do painel.

#A constante RELOCATE depois de mudar de pasta

A constante define( 'RELOCATE', true );, acrescentada em wp-config.php antes do comentário That's all, stop editing!, faz com que, depois de entrar através de wp-login.php no novo servidor, o WordPress adote o endereço atual. Segundo a documentação, só corrige os endereços do painel e não o resto da configuração, e deixá-la no ficheiro é inseguro: “Remova sempre a linha RELOCATE do wp-config.php quando terminar” (Migrating WordPress, developer.wordpress.org, tradução própria).

#Transientes na base de dados migrada

A documentação chama a atenção para os transientes, valores temporários guardados em wp_options. Podem conter endereços antigos e, como o WordPress os volta a criar sozinho, podem ser apagados com segurança na cópia migrada da base de dados. No WP-CLI isso faz-se com wp transient delete --all, e a documentação indica também uma consulta para o phpMyAdmin, precedida de uma cópia de segurança:

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

#Como mudar URLs quando o painel do WordPress não funciona

Em situações de emergência, sem acesso SSH e com o painel do WordPress em baixo por causa de um ciclo de redirecionamentos ou de ficheiros danificados, a ferramenta de confiança há mais de uma década continua a ser o script Search-Replace-DB (conhecido como SRDB), criado pela agência Interconnect/it.

Como usar o script SRDB:
1. Descarregue o ficheiro zip oficial a partir do site interconnectit.com.
2. Descompacte os ficheiros e dê à pasta um nome único e difícil de adivinhar (por exemplo srdb-sec-8f7a9d/).
3. Envie a pasta por FTP / SFTP para a pasta principal da instalação WordPress (onde está o wp-config.php).
4. Abra no browser: https://o-seu-dominio.pt/srdb-sec-8f7a9d/.
5. O script lê automaticamente os dados de acesso à base de dados a partir do wp-config.php.
6. Preencha os campos "replace" (valor antigo) e "with" (valor novo).
7. Clique em "dry run" e, depois de verificar, em "live run".
8. CRÍTICO: no fim, clique no botão vermelho "delete me" para o script se apagar do servidor.

[!CAUTION] Deixar o script Search-Replace-DB num servidor em funcionamento é uma falha de segurança crítica. Quem adivinhar o caminho do script fica com acesso total de leitura e escrita à base de dados, sem precisar de palavra-passe. Confirme sempre que a pasta foi apagada no fim do trabalho!


#Mudar URLs no Elementor, no Divi e no Gutenberg

Os construtores de páginas modernos e o editor de blocos Gutenberg acrescentam camadas de codificação dos dados que é preciso ter em conta ao atualizar URLs.

graph LR
    subgraph WP_CLI_Execution["Passo 1: base de dados"]
        A["wp search-replace"] --> B["Tabelas wp_posts, wp_postmeta, wp_options"]
    end

    subgraph Builder_Sync["Passo 2: construtores de páginas"]
        B --> C["Elementor: Tools > Replace URL"]
        B --> D["Elementor: regenerar ficheiros CSS"]
    end

    subgraph Edge_Purge["Passo 3: cache e edge"]
        C & D --> F["wp cache flush (Redis/Memcached)"]
        F --> G["Purgar a CDN (Cloudflare)"]
    end

#1. URLs nos dados JSON do Elementor

O Elementor guarda a estrutura das páginas no campo meta _elementor_data, em formato JSON, onde as barras dos URLs aparecem muitas vezes escapadas (escaped slashes):

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

Uma pesquisa normal por https://dominio-antigo.pt pode não encontrar a string com barras escapadas https:\/\/dominio-antigo.pt. Além disso, o Elementor compila as regras de estilo em ficheiros CSS estáticos na pasta wp-content/uploads/elementor/css/.

Procedimento correto depois de migrar um site com Elementor:

  1. Execute o wp search-replace normal na base de dados.
  2. Entre no painel do WordPress e vá a Elementor > Tools > Replace URL (rótulos da interface em inglês).
  3. Introduza o URL antigo e o novo e clique em Replace URL.
  4. No separador General, clique em Regenerate Files & Data.

#2. URLs nos blocos do Gutenberg

Os blocos do Gutenberg guardam os atributos de multimédia diretamente em comentários HTML dentro de post_content:

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

Tanto o wp search-replace como o Better Search Replace tratam isto sem problemas, desde que pesquisem a coluna post_content da tabela wp_posts.

#3. URLs escritos diretamente nos ficheiros do tema

Alguns temas e plugins têm endereços escritos diretamente em ficheiros PHP, CSS ou JavaScript. Nenhuma substituição na base de dados os apanha, mas é fácil encontrá-los no servidor:

grep -rn "dominio-antigo.pt" wp-content/themes/o-seu-tema/

#Mudar o domínio numa loja WooCommerce

Ao mudar o domínio de uma loja online em WooCommerce, dê especial atenção aos módulos que comunicam com sistemas de pagamento externos, transportadoras e sistemas ERP:

  1. Gateways de pagamento (Stripe, PayPal e outros):
    • A maioria dos gateways de pagamento regista nos seus painéis de programador os endereços de notificação de retorno (webhooks ou IPN). Se mudar de antigo.pt para novo.pt, as notificações de encomendas pagas continuam a ir para o endereço antigo e geram erros nas transações.
    • Depois do wp search-replace, entre no painel de cada prestador de pagamentos e atualize o endereço do webhook.
  2. Chaves e webhooks da REST API do WooCommerce:
    • Em WooCommerce > Settings > Advanced > Webhooks, confirme que os endereços de destino (Delivery URL) foram atualizados. Se os webhooks sincronizam stocks com um sistema ERP, atualize os endereços dos endpoints no software de integração.
  3. Sessões e carrinhos dos clientes:
    • A tabela wp_woocommerce_sessions guarda dados temporários dos carrinhos. Depois de mudar o domínio, convém limpar as sessões em WooCommerce > Status > Tools > Clear customer sessions, para evitar erros de tokens de sessão depois da mudança dos cookies do domínio.

#Search-replace numa base de dados grande e num cluster MySQL

Em bases de dados muito grandes, uma única passagem do wp search-replace por todas as tabelas demora muito e, durante todo esse tempo, escreve em tabelas que o site em funcionamento está a usar. A documentação do WP-CLI refere duas limitações a conhecer: as tabelas sem chave primária são ignoradas, e as opções --regex e --log tornam o trabalho bastante mais lento.

#1. Como dividir o search-replace em partes mais pequenas

O comando wp search-replace não tem opções de tamanho de lote nem de limite de linhas; a lista de opções na documentação do WP-CLI não as inclui, e as instruções que as indicam não funcionam. O trabalho divide-se de outra forma: passando os nomes das tabelas como argumentos (são aceites caracteres universais) ou excluindo tabelas com --skip-tables:

# Primeiro o conteúdo, depois os metadados, em passagens separadas
wp search-replace 'https://antigo.pt' 'https://novo.pt' wp_posts --precise --skip-columns=guid
wp search-replace 'https://antigo.pt' 'https://novo.pt' wp_postmeta --precise

# Tudo exceto uma tabela grande de registos de um plugin
wp search-replace 'https://antigo.pt' 'https://novo.pt' --all-tables --skip-tables='wp_*_log' --precise --skip-columns=guid

A opção --include-columns limita a substituição às colunas indicadas e, com --export, o número de linhas em cada instrução INSERT define-se com --export_insert_size (50 por omissão).

#2. Search-replace com replicação (Amazon Aurora, MySQL Galera)

Se a base de dados corre numa arquitetura primário e réplicas ou num cluster Galera, alterar milhões de registos de uma vez gera um enorme fluxo de dados no registo binário (binlog). Isso pode causar um atraso de replicação considerável (replication lag) nos nós de leitura.

Estratégia recomendada para ambientes de alta disponibilidade:

  • Fazer a operação numa janela de manutenção com o menor tráfego possível.
  • Desligar temporariamente os nós de réplica durante a escrita em massa.
  • Usar a flag --export para preparar o ficheiro SQL processado numa máquina de trabalho separada e importá-lo durante a janela de manutenção.

#3. Modo de manutenção durante a migração

O WP-CLI consegue ativar o modo de manutenção do WordPress, para que os visitantes não vejam o site a meio da mudança de endereço:

wp maintenance-mode activate
wp search-replace 'https://antigo.pt' 'https://novo.pt' --all-tables --precise --skip-columns=guid
wp maintenance-mode deactivate

#Passar de HTTP para HTTPS e configurar os servidores web

Se o objetivo da migração não é mudar o domínio, mas instalar um certificado SSL e passar do protocolo sem encriptação para o encriptado:

wp search-replace 'http://o-seu-dominio.pt' 'https://o-seu-dominio.pt' \
  --all-tables \
  --precise \
  --skip-columns=guid

Assim elimina o problema do Mixed Content (conteúdo misto), em que o browser bloqueia scripts, tipos de letra ou imagens servidos pelo antigo protocolo http://. Restrinja sempre a substituição ao seu próprio domínio: trocar apenas http:// por https:// em toda a base de dados alteraria também as ligações para sites externos que não suportam HTTPS.

#Redirecionamentos 301 no Nginx e no Apache

Depois de mudar o domínio na base de dados, o passo crítico do ponto de vista de SEO é redirecionar todo o tráfego do endereço antigo para o novo com o código HTTP 301 (Moved Permanently).

Configuração Nginx (/etc/nginx/sites-available/dominio-antigo.conf):

server {
    listen 80;
    listen 443 ssl http2;
    server_name dominio-antigo.pt www.dominio-antigo.pt;

    ssl_certificate /etc/letsencrypt/live/dominio-antigo.pt/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/dominio-antigo.pt/privkey.pem;

    return 301 https://dominio-novo.pt$request_uri;
}

Configuração Apache (.htaccess no servidor antigo):

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

Para confirmar que o redirecionamento devolve 301 e que o novo endereço responde com 200, basta o curl:

curl -s -o /dev/null -w "%{http_code}\n" https://dominio-antigo.pt/
curl -s -o /dev/null -w "%{http_code}\n" https://dominio-novo.pt/

#Constantes no wp-config.php e valores na base de dados

Uma prática comum em caso de avaria é forçar os URLs no ficheiro wp-config.php:

define('WP_HOME', 'https://dominio-novo.pt');
define('WP_SITEURL', 'https://dominio-novo.pt');

Convém saber como estas constantes funcionam na prática:

  • As constantes definidas em wp-config.php sobrepõem-se aos valores siteurl e home que o WordPress lê, mas não alteram os registos na base de dados. A documentação chama-lhe abertamente “fixar os valores no código” e sublinha que não é a melhor correção.
  • Os campos de endereço em Opções > Geral deixam de poder ser editados.
  • Os endereços no conteúdo dos artigos, nos anexos e nos widgets continuam a apontar para o endereço antigo.
  • Trate as constantes em wp-config.php como solução temporária; no fim, a base de dados deve ser sempre atualizada com wp search-replace.

#Lista de verificação para mudar o domínio WordPress

Antes de começar, siga um plano de trabalho estruturado:

FaseTarefaFerramenta / comando
Antes da migraçãoExportação completa da base de dadoswp db export backup-$(date +%s).sql --add-drop-table
Antes da migraçãoCópia de wp-content/uploads e .htaccessrsync / tar -czf uploads.tar.gz
Antes da migraçãoDesativar plugins de cache e minificaçãoPainel do WP / wp plugin deactivate
DuranteTeste sem gravar dos parâmetros de substituiçãowp search-replace 'old' 'new' --all-tables --dry-run
DuranteSubstituição real na base de dadoswp search-replace 'old' 'new' --all-tables --precise --skip-columns=guid
DuranteSubstituição de domínios nos construtores (Elementor)Painel > Elementor > Tools > Replace URL
Depois da migraçãoLimpar a cache de objetos e os transienteswp cache flush e wp transient delete --all
Depois da migraçãoRegenerar as ligações permanenteswp rewrite flush --hard

#Script Bash para sincronizar a base de dados WordPress entre ambientes

Em fluxos de trabalho com contentores Docker ou ambientes de desenvolvimento e staging (DDEV, Lando, LocalWP), escrever os comandos à mão demora e está sujeito a erros humanos. Nas equipas de engenharia é comum preparar um script Bash que automatiza a transferência da base de dados de produção, a importação no ambiente local, a substituição dos domínios e a limpeza das caches.

#!/usr/bin/env bash
# Script de sincronização automática da base de dados: sync-db.sh
set -eo pipefail

PROD_HOST="o-seu-servidor-de-producao.pt"
PROD_USER="deploy"
PROD_PATH="/var/www/html"
PROD_URL="https://a-sua-empresa.pt"
LOCAL_URL="https://projeto.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 A transferir a base de dados de produção por SSH..."
ssh "${PROD_USER}@${PROD_HOST}" "cd ${PROD_PATH} && wp db export - --add-drop-table" > "${DUMP_FILE}"

echo "==> 2/4 A importar a base de dados no ambiente local..."
wp db import "${DUMP_FILE}"

echo "==> 3/4 A substituir os domínios respeitando a serialização..."
wp search-replace "${PROD_URL}" "${LOCAL_URL}" \
  --all-tables \
  --precise \
  --recurse-objects \
  --skip-columns=guid \
  --report-changed-only

echo "==> 4/4 A limpar a cache e a regenerar as ligações..."
wp cache flush
wp rewrite flush --hard

echo "==> Concluído! O ambiente local está sincronizado em ${LOCAL_URL}."

#Verificar a serialização depois de terminar

Se quer ter a certeza de que nenhum campo da base de dados ficou danificado durante a migração, pode correr no WP-CLI um pequeno script PHP que verifica a integridade de todos os registos serializados da tabela 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 "Opção danificada: " . $opt->option_name . PHP_EOL;
        $broken++;
    }
}
if ($broken === 0) {
    echo "Todas as opções serializadas da tabela wp_options estão corretas." . PHP_EOL;
} else {
    echo "Encontrados " . $broken . " registos danificados!" . PHP_EOL;
}
'

Para confirmar que não sobrou o domínio antigo nas tabelas principais, uma contagem simples chega:

wp db query "SELECT COUNT(*) FROM wp_posts WHERE post_content LIKE '%dominio-antigo.pt%'"
wp db query "SELECT option_name FROM wp_options WHERE option_value LIKE '%dominio-antigo.pt%'"

#Erros depois de mudar o domínio WordPress e como corrigi-los

#1. Ciclo de redirecionamentos depois de mudar o domínio (ERR_TOO_MANY_REDIRECTS)

Se depois da mudança o site entra num ciclo infinito de redirecionamentos:

  • Confirme que siteurl e home na tabela wp_options usam exatamente o mesmo protocolo (https://) e o mesmo prefixo (com ou sem www) configurados no servidor web ou na Cloudflare.
  • Verifique a configuração SSL na Cloudflare (o modo SSL/TLS deve estar em Full (Strict) e não em Flexible).
  • Reponha o ficheiro .htaccess na versão padrão do WordPress com:
    wp rewrite flush --hard

#2. Estilos CSS e ícones desaparecidos depois da migração

  • Se o site carrega como texto simples sem estilos, as causas mais comuns são folhas de estilo e scripts que ainda apontam para o endereço antigo, conteúdo misto (Mixed Content) na passagem para HTTPS ou recursos bloqueados pela política CORS.
  • Abra a consola de programador do browser (tecla F12 > separador Console) para identificar os ficheiros carregados a partir do antigo endereço http://.

#3. Widgets ou campos ACF danificados

  • Se as regras da serialização foram ignoradas e correu um REPLACE em SQL bruto, a única saída segura é repor a base de dados a partir da exportação feita antes (wp db import backup.sql) e repetir a operação com wp search-replace --precise.

#4. Erro Allowed memory size exhausted no WP-CLI

Durante um search-replace em tabelas com muitos dados de texto (por exemplo tabelas de registos grandes ou revisões de artigos), o processo PHP no terminal pode esgotar o limite de memória:

  • Para aumentar temporariamente o limite de memória de um único comando WP-CLI, execute-o com a definição do PHP:
    php -d memory_limit=1024M /usr/local/bin/wp search-replace 'https://antigo.pt' 'https://novo.pt' --all-tables
  • Antes da migração vale também a pena apagar revisões desnecessárias e transientes expirados:
    wp transient delete --all && wp post delete $(wp post list --post_type='revision' --format=ids) --force

#5. Codificação de caracteres e collation incompatíveis

Ao mover a exportação da base de dados para um servidor mais antigo ou diferente, o servidor de destino pode não conhecer a collation usada na exportação, por exemplo utf8mb4_unicode_520_ci:

  • Se ao importar o ficheiro .sql aparecer o erro #1273 - Unknown collation: 'utf8mb4_unicode_520_ci', substitua essa string no ficheiro SQL antes de importar:
    sed -i 's/utf8mb4_unicode_520_ci/utf8mb4_unicode_ci/g' backup.sql
  • Ambas as collations guardam utf8mb4, por isso os acentos portugueses mantêm-se; muda apenas a regra de ordenação e comparação de texto.

#Resumo

Atualizar corretamente os URLs na base de dados WordPress exige perceber como funcionam o PHP e as bases de dados relacionais. Consultas SQL em bruto ou edição de ficheiros em editores de texto são o caminho mais curto para desestabilizar o site e perder configurações.

O WP-CLI com as flags --all-tables --precise --skip-columns=guid, precedido de uma cópia de segurança e de uma passagem --dry-run, mantém intactos os dados serializados e a coluna guid.

Está a planear uma modernização completa do site, uma arquitetura headless ou uma migração para plataformas de nova geração? Veja os nossos serviços de migração de WordPress para Astro e Next.js, a auditoria de Core Web Vitals e o apoio em projetos de desenvolvimento WordPress.

Próximo passo

Transforme o artigo numa implementação real

Este bloco reforça a ligação interna e conduz o leitor para o passo seguinte mais útil dentro da arquitetura do site.

Quer implementar isto no seu site?

Se quer transformar o artigo em melhorias concretas, redesign ou num plano de implementação, posso fechar o escopo e executar.

Cluster relacionado

Explorar outros serviços WordPress e base de conhecimento

Reforce o seu negócio com suporte técnico profissional em áreas-chave do ecossistema WordPress.

Porque é que um UPDATE em SQL com REPLACE estraga a base de dados WordPress#
O WordPress guarda configurações complexas, widgets, definições de temas e campos ACF como arrays PHP serializados, por exemplo s:25:"https://dominio-antigo.pt". A função REPLACE em SQL troca o texto, mas não atualiza o contador de caracteres (aqui, 25). Ao ler o valor, o PHP deteta a diferença de comprimento e rejeita toda a estrutura como corrompida.
Qual é a ferramenta mais segura para mudar o domínio na base de dados WordPress#
A ferramenta mais recomendada é o WP-CLI oficial com o comando wp search-replace. Segundo a documentação do WP-CLI, o comando trata corretamente os dados serializados do PHP: desserializa-os, substitui o texto, recalcula os comprimentos e grava-os de volta.
É preciso alterar os URLs na coluna guid da tabela wp_posts#
Não. A coluna guid (Globally Unique Identifier) serve aos leitores de RSS como identificador fixo e único de cada artigo. A documentação oficial do WordPress diz que a coluna guid nunca deve ser alterada, por isso no WP-CLI usa-se a flag --skip-columns=guid.
Como atualizar os URLs num alojamento partilhado sem acesso SSH#
Sem acesso SSH, a documentação do WordPress indica o plugin Better Search Replace (mantido pela WP Engine) ou o script Search and Replace for WordPress Databases da Interconnect/it. O script tem de ser apagado do servidor logo que o trabalho termine.
O que são dados serializados no WordPress#
Serialização é a forma que o PHP tem de converter arrays e objetos em strings que se podem guardar numa base de dados. O WordPress usa-a muito em widgets, opções de temas, definições de plugins e metadados de artigos. O formato inclui indicadores de tipo e prefixos de comprimento que têm de se manter exatos.
O que fazer se os widgets desaparecerem depois da migração#
Se os widgets desaparecem, os dados serializados ficaram corrompidos. Restaure a cópia de segurança com wp db import backup.sql e repita a migração com uma ferramenta que respeite a serialização, como o WP-CLI ou o Better Search Replace.

Precisa de FAQ adaptado ao setor e mercado? Criamos uma versão alinhada com os seus objetivos de negócio.

Fale connosco

Artigos Relacionados

Benchmarks de alojamento WordPress 2026

Os testes comparativos Review Signal de Kevin Ohashi regressaram em 2026 após três anos de pausa, alimentados por uma nova plataforma de testes de carga em código aberto. Decompomos os cinco escalões de preço mais WooCommerce, nomeamos os vencedores, nomeamos os alojamentos que ficaram de fora e traduzimos os dados para agências europeias.