Saneamento de URLs no WordPress: Como transformei 450 erros em dados limpos (Case Real)

No universo da Engenharia de Dados e da Arquitetura Web, a qualidade da informação vem antes de qualquer análise. Antes de falarmos sobre métricas de conversão ou Business Intelligence, precisamos enfrentar um inimigo silencioso: a sujeira nos dados. Este é um case real de Saneamento de URLs no WordPress.

Em um ambiente WordPress de alta escala, anos de conteúdo e campanhas espalharam milhares de URLs da Hotmart pelo banco. O resultado foi um rastro de parâmetros obsoletos (src, utm, sck) e até resíduos como u0022, criando ruído, inconsistência e risco real para SEO, performance e conversão.

O objetivo não era “deixar links bonitos”. Era restaurar a integridade do sistema com Data Sanitization, mantendo apenas o que sustenta o negócio, com uma regra crítica: preservar checkoutMode=10 quando necessário.

Aqui eu documento a base do processo e a lógica de decisão que torna a limpeza segura. Em seguida, mostro a execução em lote e o refinamento dos casos mais problemáticos em Execução do saneamento de URLs no WordPress. Por fim, fecho com auditoria final, pós-operatório (caches e CSS) e o impacto direto em dados e receita em: “Auditoria e impacto do saneamento de URLs no WordPress“.

Ferramentas e Ambiente para Saneamento de URLs no WordPress

Muitos desenvolvedores questionam: por que não utilizar um comando SQL simples diretamente no banco de dados? A resposta reside na natureza do problema. O comando REPLACE do SQL é uma ferramenta literal, não interpretativa.

O SQL funciona perfeitamente quando sabemos exatamente o que buscar e pelo que substituir. Ele troca “texto A” por “texto B”. No entanto, nosso desafio envolvia variáveis dinâmicas e imprevisíveis.

Cada URL da Hotmart possuía uma cauda de parâmetros única. O SQL não possui a inteligência nativa para dizer: “mantenha o ID do produto, verifique se existe o parâmetro de checkout e descarte o restante”.

Para manipular padrões complexos, a lógica precisa ser procedural. Foi necessário utilizar uma linguagem de programação capaz de processar condicionais. Por isso, escolhemos a integração do WP-CLI com PHP.

O WP-CLI (WordPress Command Line Interface) atua como uma ponte. Ele nos permite interagir com a infraestrutura do WordPress diretamente pelo terminal, sem a sobrecarga de processamento de um navegador web.

Ao injetar scripts PHP via terminal, ganhamos acesso ao poder das Expressões Regulares (Regex). O Regex não busca palavras; ele busca padrões de caracteres, permitindo identificar e isolar o ID de cada produto.

Com essa tecnologia, construímos um algoritmo de “sanitização inteligente”. O código não apenas apaga dados; ele lê a URL, interpreta sua estrutura, toma decisões baseadas em regras de negócio e reconstrói o dado limpo.

Por fim, a segurança da operação foi garantida por protocolos rígidos. Em engenharia de dados, nunca operamos em produção sem uma rede de segurança. O backup completo do banco de dados foi o passo zero.

Além do backup, trabalhamos com o conceito de “Dry Run” (Simulação). Nossos scripts foram projetados para rodar inicialmente em modo de leitura, gerando relatórios de “o que aconteceria se…”.

Essa etapa de homologação permitiu auditar a lógica do algoritmo antes de qualquer alteração real. Somente após a validação matemática das substituições propostas, o comando de escrita foi executado.


Diagnóstico e Mapeamento

Antes de qualquer intervenção cirúrgica no banco de dados, é mandatório entender a extensão do problema. Em engenharia de dados, operar às cegas é a receita para o desastre. Por isso, a primeira etapa não foi corretiva, mas investigativa.

Precisávamos de um “Raio-X” completo de todas as URLs da Hotmart presentes no ecossistema do site, independentemente de estarem visíveis em um artigo de blog ou escondidas nas configurações de um plugin de SEO.

Criando o Rastreador (Crawler) via wp eval-file

O WordPress possui milhares de linhas e tabelas. Fazer essa busca manualmente seria inviável. A solução foi criar um script personalizado em PHP para rodar via WP-CLI.

Optamos pelo comando wp eval-file em vez de wp eval (linha única) para evitar conflitos de sintaxe com aspas no terminal e permitir uma lógica mais robusta. O script atua como um crawler interno: ele varre o conteúdo, extrai padrões específicos usando Regex (Expressões Regulares) e limpa a formatação de escape (barras invertidas comuns em bancos de dados).

Abaixo, o código utilizado para mapear o cenário. Ele ignora duplicatas exatas, mas lista todas as variações de parâmetros, nos dando a dimensão real da sujeira.

<?php
/**
 * Script de Auditoria e Mapeamento de URLs Hotmart
 * Execução via terminal: wp eval-file rastreador.php
 */

global $wpdb;

echo "\n--------------------------------------------------\n";
echo "🔎 INICIANDO O RASTREADOR DE DADOS\n";
echo "--------------------------------------------------\n";

// Regex desenhado para capturar http/https + domínio + qualquer cauda
// O padrão para apenas ao encontrar espaço, aspas ou tags HTML
$regex = "/https?:\/\/[^\s\"'<]*hotmart\.com[^\s\"'<]*/i";

$found_urls = [];

// 1. Varredura na Tabela de Posts (Conteúdo visível)
echo "1. Analisando wp_posts... ";
$posts = $wpdb->get_results("SELECT post_content FROM {$wpdb->posts} WHERE post_content LIKE '%hotmart.com%'");
foreach ($posts as $p) {
    if (preg_match_all($regex, $p->post_content, $matches)) {
        foreach ($matches[0] as $url) {
            // stripslashes remove as barras de escape do JSON (ex: https:\/\/ vira https://)
            $found_urls[] = stripslashes($url); 
        }
    }
}
echo "OK (" . count($posts) . " registros analisados).\n";

// 2. Varredura na Tabela de Metadados (Configurações ocultas)
echo "2. Analisando wp_postmeta... ";
$metas = $wpdb->get_results("SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_value LIKE '%hotmart.com%'");
foreach ($metas as $m) {
    if (preg_match_all($regex, $m->meta_value, $matches)) {
        foreach ($matches[0] as $url) {
            $found_urls[] = stripslashes($url);
        }
    }
}
echo "OK (" . count($metas) . " registros analisados).\n";

// 3. Consolidação dos Dados
// array_unique garante que veremos cada variação de URL apenas uma vez
$unique_urls = array_unique($found_urls);
sort($unique_urls);

echo "\n--------------------------------------------------\n";
echo "RELATÓRIO DE DIAGNÓSTICO (Total: " . count($unique_urls) . " URLs únicas)\n";
echo "--------------------------------------------------\n\n";

foreach ($unique_urls as $url) {
    echo $url . "\n";
}
echo "\n";

Análise de Padrões: Identificando as variações de sujeira

Ao executar o script acima, o retorno do terminal confirmou a hipótese de poluição severa dos dados. O que deveria ser uma lista de produtos únicos se revelou um emaranhado de parâmetros de rastreamento órfãos.

Identificamos três categorias críticas de “sujeira” nos links:

  1. Parâmetros de Origem (Source): Centenas de URLs continham variações de ?src=facebook, ?src=email_marketing, ?utm_source=blog. Isso fragmenta a análise de dados, pois o mesmo produto é contabilizado como dezenas de URLs diferentes.
  2. Lixo de Código (Encoding): Encontramos URLs terminando em u0022 ou u003e. Isso são resíduos de codificação Unicode de JSON que foram salvos incorretamente junto com o link, frequentemente quebrando a funcionalidade do clique.
  3. Inconsistência de Checkout: Alguns links possuíam o parâmetro vital checkoutMode=10, outros não, e alguns o tinham duplicado ou mal formatado.

A parte mais complexa do diagnóstico não estava nos textos dos artigos, mas onde os olhos não veem: a tabela wp_postmeta.

Plugins modernos como Rank Math (SEO) e GenerateBlocks (Design) não salvam dados como texto simples. Eles utilizam arrays serializados ou objetos JSON.

Imagine que o WordPress salva as configurações de um bloco de botão não como “Link: http…”, mas como um pacote de dados codificado:

{"tipo":"botao","link":"https:\/\/pay.hotmart.com\/XYZ","cor":"azul"}.

Se utilizássemos uma substituição simples de texto (SQL REPLACE), correríamos o risco de corromper a estrutura desse pacote JSON, invalidando o bloco inteiro ou as configurações de SEO da página.

O nosso rastreador foi programado especificamente para ler dentro dessas estruturas (usando stripslashes e varredura de meta_value), garantindo que até os links “escondidos” dentro das configurações complexas dos plugins fossem mapeados para a limpeza futura. Sem isso, a sanitização seria superficial e incompleta.

A Lógica do Algoritmo de Limpeza

Mapear o problema foi apenas o primeiro passo. A verdadeira engenharia começou ao definir como tratar cada variação de URL encontrada. Não bastava passar uma borracha em tudo; precisávamos de critérios.

Aqui entra o conceito de “Funil de Decisão”. Em vez de tentar limpar a URL existente removendo pedaço por pedaço, adotamos uma abordagem reconstrutiva.

O algoritmo não “conserta” o link velho. Ele identifica o ID do produto (o ativo principal), verifica se existem regras de exceção e, então, descarta a URL antiga inteira para construir uma nova, absolutamente limpa, do zero.

O “Funil de Decisão”: O que fica vs. O que sai

A lógica do script opera separando o “Sinal” do “Ruído”. O Sinal é a URL base que contém o ID do produto (ex: go.hotmart.com/XYZ123). O Ruído é tudo que vem depois: parâmetros de rastreamento (src), códigos de afiliados e lixo de formatação.

A regra padrão do funil é estrita: se não for essencial para a transação, é eliminado. Isso garante que métricas de src antigas e fragmentadas não poluam a base de dados futura.

Tratamento de Exceções: A regra de ouro do checkoutMode=10

Toda regra possui sua exceção crítica. No nosso caso, o parâmetro checkoutMode=10 altera o comportamento do link, levando o usuário direto ao pagamento em vez da página de vendas. Remover isso quebraria a estratégia de conversão.

O algoritmo precisava ser inteligente o suficiente para distinguir entre “lixo” (como src=facebook) e “funcionalidade” (checkoutMode).

Se o script detecta a presença desse parâmetro na “cauda” suja da URL antiga, ele ativa a flag de preservação. Porém, ele não preserva o texto original (que poderia estar contaminado com u0022). Ele adiciona uma nova string limpa ao final do ID.

Padronização de CamelCase: Convertendo checkoutmode para checkoutMode

A consistência é a melhor amiga da análise de dados. Encontramos variações como checkoutmode (minúsculo) e CheckOutMode misturadas no banco. Para um computador, ?a=1 e ?A=1 podem ser coisas diferentes dependendo do sistema.

Implementamos uma normalização forçada. Independentemente de como o parâmetro foi escrito no passado, o algoritmo o reescreve seguindo o padrão CamelCase oficial da plataforma: checkoutMode=10.

Abaixo, o trecho do código PHP que implementa essa lógica de decisão e reconstrução:

// Trecho do algoritmo de decisão (Funil)

// 1. Separa a BASE (ID do Produto) do RESTO (Lixo/Parâmetros)
// O Regex captura o ID no grupo 1 e o resto no grupo 2
if (preg_match('/^(https?:\/\/[^\/]*hotmart\.com\/[a-zA-Z0-9]+)(.*)$/i', $dirty_url, $parts)) {
    
    $base_url = $parts[1]; // Ex: https://pay.hotmart.com/H12345
    $tail     = $parts[2]; // Ex: ?src=fb&checkoutmode=10u0022...

    // 2. A Regra de Ouro: Verifica se checkoutMode existe (Case Insensitive)
    // stripos permite achar 'checkoutmode' mesmo se estiver minúsculo
    if (stripos($tail, 'checkoutmode=10') !== false) {
        
        // CENÁRIO A: É um link de Checkout Direto.
        // Reconstruímos a URL com o parâmetro PADRONIZADO (CamelCase).
        // Note que ignoramos o $tail original. O lixo é descartado.
        $clean_url = $base_url . "?checkoutMode=10";

    } else {
        
        // CENÁRIO B: Link padrão.
        // Mantemos apenas a base. Removemos src, utm, e qualquer outro ruído.
        $clean_url = $base_url;
    }

    // 3. Se a URL reconstruída for diferente da original, agendamos a troca.
    if ($dirty_url !== $clean_url) {
        $commands[] = "wp search-replace '$dirty_url' '$clean_url' --all-tables";
    }
}

Com o problema mapeado e a lógica de sanitização definida, o próximo passo foi transformar estratégia em execução com segurança. Em operações desse tipo, limpar não é “substituir texto”: é garantir que cada alteração respeite a integridade do WordPress e a regra de negócio do checkoutMode=10.

Para isso, eu construí uma abordagem em camadas, com scripts geradores, auditoria prévia e execução via terminal, reduzindo risco e aumentando controle. É nessa etapa que muita gente erra por pressa e cria um problema maior do que o original.

A continuação prática, com os scripts, execução em lote e correção dos casos “teimosos”, está no próximo post: Execução da limpeza via WP-CLI.

Deixe um comentário