En el mundo de Ingeniería de Datos y Arquitectura Web, la calidad de la información es prioritaria antes de cualquier análisis. Antes de hablar de métricas de conversión o Inteligencia Empresarial, debemos enfrentarnos a un enemigo silencioso: la contaminación de datos. Este es un caso real de Sanitización de URL en WordPress.
En un entorno de WordPress de gran escala, años de contenido y campañas han esparcido miles de URLs de Hotmart por toda la base de datos. El resultado fue un rastro de parámetros obsoletos (src, utm, sck) e incluso residuos como u0022, creando ruido, inconsistencias y un riesgo real para el SEO, rendimiento y conversión.
El objetivo no era «hacer que los enlaces se vean bonitos». Se trataba de restaurar la integridad del sistema con Sanitización de Datos, manteniendo solo lo que apoya el negocio, con una regla crítica: preservar checkoutMode=10 cuando sea necesario.
Aquí documentaré las bases del proceso y la lógica de decisión que hace que la limpieza sea segura. A continuación, mostraré la ejecución por lotes y el refinamiento de los casos más problemáticos en Ejecución de la Sanitización de URL en WordPress. Finalmente, concluiré con una auditoría final, postoperatoria (cachés y CSS), y el impacto directo en los datos y los ingresos en: «Auditoría e Impacto de la Sanitización de URL en WordPress«.
Tabla de Contenidos
Herramientas y Entorno para la Sanitización de URL en WordPress
Muchos desarrolladores preguntan: ¿por qué no usar un simple comando SQL directamente en la base de datos? La respuesta radica en la naturaleza del problema. El comando REPLACE en SQL es una herramienta literal, no interpretativa.
SQL funciona perfectamente cuando sabemos exactamente qué buscar y qué reemplazar. Cambia «texto A» por «texto B». Sin embargo, nuestro desafío involucraba variables dinámicas e impredecibles.
Cada URL de Hotmart tenía una cola única de parámetros. SQL no tiene la inteligencia nativa para decir: «mantén el ID del producto, verifica si existe el parámetro de checkout y descarta el resto».
Para manipular patrones complejos, la lógica necesita ser procedural. Era necesario usar un lenguaje de programación capaz de procesar condicionales. Por eso elegimos la integración de WP-CLI con PHP.
El WP-CLI (Interfaz de Línea de Comando de WordPress) actúa como un puente. Nos permite interactuar con la infraestructura de WordPress directamente desde la terminal, sin la sobrecarga de procesamiento de un navegador web.
Al inyectar scripts de PHP a través de la terminal, obtenemos acceso al poder de las Expresiones Regulares (Regex). Regex no busca palabras; busca patrones de caracteres, lo que nos permite identificar y aislar el ID de cada producto.
Con esta tecnología, construimos un algoritmo de «sanitización inteligente». El código no solo elimina datos; lee la URL, interpreta su estructura, toma decisiones basadas en reglas de negocio y reconstruye los datos limpios.
Finalmente, la seguridad de la operación se aseguró mediante protocolos estrictos. En ingeniería de datos, nunca operamos en producción sin una red de seguridad. Una copia de seguridad completa de la base de datos fue el paso cero.
Además de la copia de seguridad, trabajamos con el concepto de «Dry Run» (Simulación). Nuestros scripts fueron diseñados para ejecutarse inicialmente en modo de lectura, generando informes de «lo que ocurriría si…».
Este paso de validación nos permitió auditar la lógica del algoritmo antes de cualquier cambio real. Solo después de la validación matemática de las sustituciones propuestas se ejecutó el comando de escritura.
Diagnóstico y Mapeo
Antes de cualquier intervención quirúrgica en la base de datos, es obligatorio entender la magnitud del problema. En ingeniería de datos, operar a ciegas es una receta para el desastre. Por lo tanto, el primer paso no fue correctivo sino investigativo.
Necesitábamos una «Radiografía» completa de todas las URLs de Hotmart presentes en el ecosistema del sitio, independientemente de si eran visibles en un artículo de blog o estaban ocultas en la configuración de un plugin de SEO.
Creando el Crawler a través de wp eval-file
WordPress tiene miles de líneas y tablas. Buscar esto manualmente sería inviable. La solución fue crear un script PHP personalizado para ejecutar a través de WP-CLI.
Optamos por el comando wp eval-file en lugar de wp eval (una sola línea) para evitar conflictos de sintaxis con las comillas en la terminal y permitir una lógica más robusta. El script actúa como un crawler interno: escanea el contenido, extrae patrones específicos usando Regex (Expresiones Regulares) y limpia el formato de escape (barra invertida común en bases de datos).
Abajo está el código utilizado para mapear el escenario. Ignora duplicados exactos pero lista todas las variaciones de parámetros, dándonos la verdadera dimensión de la contaminación.
<?php
/**
* Script de Auditoría y Mapeo de URL de Hotmart
* Ejecución a través de terminal: wp eval-file rastreador.php
*/
global $wpdb;
echo "n--------------------------------------------------n";
echo "🔎 INICIANDO RASTREADOR DE DATOSn";
echo "--------------------------------------------------n";
// Regex diseñado para capturar http/https + dominio + cualquier sufijo
// El patrón solo coincide al encontrar espacios, comillas o etiquetas HTML
$regex = "/https?://[^s"'<]*hotmart.com[^s"'<]*/i";
$found_urls = [];
// 1. Escanear la Tabla de Posts (Contenido visible)
echo "1. Analizando 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 elimina las barras de escape del JSON (ex: https:// se convierte en https://)
$found_urls[] = stripslashes($url);
}
}
}
echo "OK (" . count($posts) . " registros analizados).n";
// 2. Escanear la Tabla de Metadatos (Configuraciones ocultas)
echo "2. Analizando 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 analizados).n";
// 3. Consolidación de Datos
// array_unique asegura que veamos cada variación de URL solo una vez
$unique_urls = array_unique($found_urls);
sort($unique_urls);
echo "n--------------------------------------------------n";
echo "INFORME DIAGNÓSTICO (Total: " . count($unique_urls) . " URLs únicas)n";
echo "--------------------------------------------------nn";
foreach ($unique_urls as $url) {
echo $url . "n";
}
echo "n";
Análisis de Patrones: Identificación de Variaciones de Desorden
Al ejecutar el script anterior, la salida de la terminal confirmó la hipótesis de una grave contaminación de datos. Lo que debería haber sido una lista de productos únicos resultó ser un enredo de parámetros de seguimiento huérfanos.
Identificamos tres categorías críticas de «desorden» en los enlaces:
- Parámetros de Origen: Cientos de URLs contenían variaciones de
?src=facebook,?src=email_marketing,?utm_source=blog. Esto fragmenta el análisis de datos, ya que el mismo producto se cuenta como docenas de URLs diferentes. - Basura de Código (Codificación): Encontramos URLs que terminaban en
u0022ou003e. Estos son residuos de codificación JSON Unicode que se guardaron incorrectamente junto con el enlace, rompiendo a menudo la funcionalidad de clic. - Inconsistencia en el Checkout: Algunos enlaces tenían el parámetro vital
checkoutMode=10, otros no, y algunos lo tenían duplicado o mal formateado.
El Desafío de la Serialización: Detección de Enlaces en wp_postmeta
La parte más compleja del diagnóstico no estaba en los textos de los artículos, sino donde los ojos no ven: la tabla wp_postmeta.
Plugins modernos como Rank Math (SEO) y GenerateBlocks (Diseño) no guardan datos como texto plano. Usan arreglos serializados o objetos JSON.
Imagina que WordPress guarda la configuración de un bloque de botón no como «Enlace: http…», sino como un paquete de datos codificado:
{"type":"button","link":"https://pay.hotmart.com/XYZ","color":"blue"}.
Si usáramos un simple reemplazo de texto (SQL REPLACE), correríamos el riesgo de corromper la estructura de este paquete JSON, invalidando todo el bloque o la configuración SEO de la página.
Nuestro rastreador fue programado específicamente para leer dentro de estas estructuras (usando stripslashes y escaneando meta_value), asegurando que incluso los enlaces «ocultos» dentro de las configuraciones complejas de los plugins fueran mapeados para una futura limpieza. Sin esto, la sanitización sería superficial e incompleta.
La Lógica del Algoritmo de Limpieza
Mapear el problema fue solo el primer paso. La verdadera ingeniería comenzó al definir cómo manejar cada variación de URL encontrada. No era suficiente con limpiar todo; necesitábamos criterios.
Aquí entra el concepto de «Embudo de Decisión». En lugar de intentar limpiar la URL existente eliminando pieza por pieza, adoptamos un enfoque reconstructivo.
El algoritmo no «arregla» el enlace antiguo. Identifica el ID del producto (el activo principal), verifica las reglas de excepción y luego descarta toda la URL antigua para construir una nueva, absolutamente limpia, desde cero.
El «Embudo de Decisión»: Qué se Mantiene vs. Qué se Elimina
La lógica del script opera separando la «Señal» del «Ruido». La Señal es la URL base que contiene el ID del producto (por ejemplo, go.hotmart.com/XYZ123). El Ruido es todo lo que viene después: parámetros de seguimiento (src), códigos de afiliados y basura de formato.
La regla estándar del embudo es estricta: si no es esencial para la transacción, se elimina. Esto asegura que las métricas src antiguas y fragmentadas no contaminen la futura base de datos.
Manejo de Excepciones: La Regla de Oro de checkoutMode=10
Cada regla tiene su excepción crítica. En nuestro caso, el parámetro checkoutMode=10 altera el comportamiento del enlace, llevando al usuario directamente al pago en lugar de a la página de ventas. Eliminar esto rompería la estrategia de conversión.
El algoritmo necesitaba ser lo suficientemente inteligente como para distinguir entre «basura» (como src=facebook) y «funcionalidad» (checkoutMode).
Si el script detecta la presencia de este parámetro en el sufijo «sucio» de la URL antigua, activa la bandera de preservación. Sin embargo, no preserva el texto original (que podría estar contaminado con u0022). Agrega una nueva cadena limpia al final del ID.
Estandarización CamelCase: Convirtiendo checkoutmode a checkoutMode
La consistencia es la mejor amiga del análisis de datos. Encontramos variaciones como checkoutmode (minúsculas) y CheckOutMode mezcladas en la base de datos. Para un ordenador, ?a=1 y ?A=1 pueden ser cosas diferentes dependiendo del sistema.
Implementamos una normalización forzada. Independientemente de cómo se haya escrito el parámetro en el pasado, el algoritmo lo reescribe siguiendo el patrón oficial CamelCase de la plataforma: checkoutMode=10.
A continuación se muestra el fragmento de código PHP que implementa esta lógica de toma de decisiones y reconstrucción:
// Fragmento del algoritmo de decisión (Embudo)
// 1. Separa la BASE (ID del producto) del RESTO (Basura/Parámetros)
// La expresión regular captura el ID en el grupo 1 y el resto en el grupo 2
if (preg_match('/^(https?://[^/]*hotmart.com/[a-zA-Z0-9]+)(.*)$/i', $dirty_url, $parts)) {
$base_url = $parts[1]; // Ej: https://pay.hotmart.com/H12345
$tail = $parts[2]; // Ej: ?src=fb&checkoutmode=10u0022...
// 2. La Regla de Oro: Verifica si checkoutMode existe (Sin distinción de mayúsculas y minúsculas)
// stripos permite encontrar 'checkoutmode' incluso si está en minúsculas
if (stripos($tail, 'checkoutmode=10') !== false) {
// ESCENARIO A: Es un enlace de pago directo.
// Reconstruimos la URL con el parámetro ESTANDARIZADO (CamelCase).
// Tengan en cuenta que ignoramos el $tail original. La basura se descarta.
$clean_url = $base_url . "?checkoutMode=10";
} else {
// ESCENARIO B: Enlace estándar.
// Solo mantenemos la base. Eliminamos src, utm y cualquier otro ruido.
$clean_url = $base_url;
}
// 3. Si la URL reconstruida es diferente de la original, programamos el cambio.
if ($dirty_url !== $clean_url) {
$commands[] = "wp search-replace '$dirty_url' '$clean_url' --all-tables";
}
}
Con el problema mapeado y la lógica de saneamiento definida, el siguiente paso fue transformar la estrategia en ejecución de manera segura. En operaciones de este tipo, saneamiento no es «reemplazar texto»: es asegurar que cada cambio respete la integridad de WordPress y la regla de negocio de checkoutMode=10.
Para lograr esto, construí un enfoque por capas, con scripts generadores, auditoría previa y ejecución a través de la terminal, reduciendo riesgos y aumentando el control. Es en esta etapa donde muchas personas cometen errores por apresuramiento y crean un problema mayor que el original.
La continuación práctica, con scripts, ejecución por lotes y corrección de los casos «rebeldes», está en la próxima publicación: Ejecución de la limpieza de URLs a través de WP-CLI.