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:
sindica 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:
- O WordPress lê a linha da base de dados e passa-a à função
unserialize(). - A função lê o cabeçalho
s:34e espera exatamente 34 caracteres. - 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. - O analisador do PHP emite o erro
PHP Notice: unserialize(): Error at offset...e devolvefalse. - O tema ou o plugin recebe
falseem vez do array de opções esperado. - 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 colunaguidnão deve ser alterada porque os leitores de feeds RSS a usam para detetar artigos novos. Se oguidmudar, 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-tableSe a base de dados ficar danificada, repõe o estado original em segundos:
wp db import backup-antes-migracao-*.sqlPasso 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-runO 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-onlyO 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 colunaguidda tabelawp_postse 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-prefixA 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_siteewp_blogs, onde ficam o domínio e o caminho da rede e de cada subsite, - as opções
home,siteurlefileupload_urlna tabela de opções de cada site (wp_options,wp_2_optionse seguintes), - ao passar de subdomínios para subdiretórios ou vice-versa: o ficheiro
.htaccesse a constanteSUBDOMAIN_INSTALLemwp-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.sqlPassar 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-runMudar 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:
| Forma | Quando usar | Cuidado a ter |
|---|---|---|
wp option update no WP-CLI | Tem SSH e o painel não funciona | Só 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 depressa | Os valores ficam fixos no código e os campos em Opções > Geral deixam de ser editáveis |
update_option() no functions.php do tema | Só tem FTP | O código tem de ser removido logo após o primeiro carregamento do painel |
Constante RELOCATE | Site movido para outra pasta ou outro servidor | Só corrige os endereços do painel e deixá-la no ficheiro é inseguro |
Edição de wp_options no phpMyAdmin | Só tem o painel de alojamento | Primeiro 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=guidAlterar 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-DBnum 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)"]
end1. 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:
- Execute o
wp search-replacenormal na base de dados. - Entre no painel do WordPress e vá a Elementor > Tools > Replace URL (rótulos da interface em inglês).
- Introduza o URL antigo e o novo e clique em Replace URL.
- 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:
- 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.ptparanovo.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.
- 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
- 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.
- Sessões e carrinhos dos clientes:
- A tabela
wp_woocommerce_sessionsguarda 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.
- A tabela
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=guidA 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
--exportpara 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 deactivatePassar 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=guidAssim 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.phpsobrepõem-se aos valoressiteurlehomeque 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.phpcomo solução temporária; no fim, a base de dados deve ser sempre atualizada comwp search-replace.
Lista de verificação para mudar o domínio WordPress
Antes de começar, siga um plano de trabalho estruturado:
| Fase | Tarefa | Ferramenta / comando |
|---|---|---|
| Antes da migração | Exportação completa da base de dados | wp db export backup-$(date +%s).sql --add-drop-table |
| Antes da migração | Cópia de wp-content/uploads e .htaccess | rsync / tar -czf uploads.tar.gz |
| Antes da migração | Desativar plugins de cache e minificação | Painel do WP / wp plugin deactivate |
| Durante | Teste sem gravar dos parâmetros de substituição | wp search-replace 'old' 'new' --all-tables --dry-run |
| Durante | Substituição real na base de dados | wp search-replace 'old' 'new' --all-tables --precise --skip-columns=guid |
| Durante | Substituição de domínios nos construtores (Elementor) | Painel > Elementor > Tools > Replace URL |
| Depois da migração | Limpar a cache de objetos e os transientes | wp cache flush e wp transient delete --all |
| Depois da migração | Regenerar as ligações permanentes | wp 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
siteurlehomena tabelawp_optionsusam exatamente o mesmo protocolo (https://) e o mesmo prefixo (com ou semwww) 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
.htaccessna 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
REPLACEem 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 comwp 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
.sqlaparecer 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.







