Como impedir contenido duplicado con verificación previa en PHP en WordPress

Contents

Introducción

El contenido duplicado es un problema común en sitios WordPress que afecta al SEO, la experiencia de usuario y la gestión interna. Este artículo explica en detalle cómo impedir la creación de contenido duplicado mediante una verificación previa en PHP, integrándose con el flujo de guardado de WordPress. Incluye técnicas seguras y prácticas —cálculo de huellas (hash), comprobaciones previas al insertado, notificaciones en el admin, manejo en formularios front-end y opciones para detección difusa— además de recomendaciones de rendimiento y migración.

Estrategia general

  • Normalizar el título y contenido (quitar HTML, espacios, convertir a minúsculas).
  • Calcular una huella (hash) del contenido relevante (por ejemplo sha1 de título contenido).
  • Comprobar en la base de datos si ya existe esa huella antes de permitir publicar/crear el post.
  • Guardar la huella en postmeta cuando el post se guarda definitivamente para futuras comprobaciones rápidas.
  • Opcional: detección difusa (similaridad con levenshtein o similitud porcentual) para evitar copias con ligeras variaciones.

Ventajas de este enfoque

  • Rápido y determinista: comparar hashes es muy eficiente.
  • Integración nativa con hooks de WordPress (pre-insert, save_post).
  • Se puede aplicar tanto en el admin como en formularios públicos (AJAX).
  • Permite acciones configurables: bloquear, convertir a borrador, o avisar al usuario.

Detalles de implementación

Debajo se muestran los bloques principales de código. Todos los ejemplos están preparados para pegar en el archivo functions.php de un tema hijo o en un plugin propio. Recuerde probar en un entorno de desarrollo antes de desplegar en producción.

1) Función para normalizar y calcular hash

Normalice eliminando HTML, múltiples espacios y convirtiendo a minúsculas. Luego calcule un hash (sha1 o md5).


2) Comprobación previa antes de insertar o publicar

Hook recomendado: wp_insert_post_data, que permite interceptar los datos antes de que WordPress haga el INSERT/UPDATE. Podemos, si detectamos duplicado, cambiar el estado del post a draft y añadir un flag para mostrar un aviso al usuario.

 postarr[post_type],
        post_status    => array( publish, draft, pending, future ),
        meta_query     => array(
            array(
                key   => _mi_content_hash,
                value => hash,
            ),
        ),
        fields         => ids,
        posts_per_page => 1,
        post__not_in   => isset( postarr[ID] )  ! empty( postarr[ID] ) ? array( intval( postarr[ID] ) ) : array(),
    )
    q = new WP_Query( args )

    if ( q->have_posts() ) {
        // Se encontró duplicado: evitar publicación cambiando a borrador
        // También marcamos un flag temporal para mostrar aviso después
        add_filter( redirect_post_location, function( location ) {
            return add_query_arg( mi_duplicate_detected, 1, location )
        } )

        // Asegurar que no se publique — forzamos draft si intentaban publicar
        if ( data[post_status] === publish ) {
            data[post_status] = draft
        }

        // Guardamos el hash en el array para procesarlo después (save_post)
        if ( isset( postarr[ID] )  ! empty( postarr[ID] ) ) {
            // En actualización, no necesitamos más, save_post lo guardará
        } else {
            // En creación, podemos pasar el hash por post_content_filtered para recuperarlo
            data[post_content_filtered] = data[post_content_filtered] . n
        }
    }

    wp_reset_postdata()
    return data
}
?>

3) Guardar el hash en postmeta cuando el post se guarda

Hook: save_post. Guardamos permanentemente la huella para futuras búsquedas.

post_type, allowed_types, true ) ) {
        return
    }

    // Obtener título y contenido actuales
    title   = post->post_title
    content = post->post_content
    hash    = mi_normalizar_y_hash_post( title, content )

    // Guardar meta
    update_post_meta( post_ID, _mi_content_hash, hash )
}
?>

4) Mostrar aviso en el área de administración cuando se bloquea por duplicado

Usamos la query arg añadida en el filtro anterior para mostrar un admin notice claro.

Duplicado detectado: Se ha detectado contenido similar en otra entrada. La publicación ha quedado en borrador. Revise y actualice el contenido o confirme que desea crear una entrada duplicada.

} } ?>

5) Verificación en formularios front-end (AJAX) antes de enviar

Para formularios públicos (por ejemplo formulario de envío de posts desde el frontend) es buena práctica verificar duplicados mediante petición AJAX y devolver un resultado antes de enviar el formulario final.

 Nonce inválido ), 400 )
    }

    title   = isset( _POST[title] ) ? wp_unslash( _POST[title] ) : 
    content = isset( _POST[content] ) ? wp_unslash( _POST[content] ) : 

    hash = mi_normalizar_y_hash_post( title, content )

    args = array(
        post_type      => array( post, page ),
        post_status    => array( publish, draft, pending ),
        meta_query     => array(
            array(
                key   => _mi_content_hash,
                value => hash,
            ),
        ),
        fields         => ids,
        posts_per_page => 1,
    )
    q = new WP_Query( args )

    if ( q->have_posts() ) {
        wp_send_json_success( array( duplicate => true, message => Contenido similar ya existe ) )
    } else {
        wp_send_json_success( array( duplicate => false ) )
    }
}
?>

En JavaScript del front-end debe invocarse la acción AJAX antes de enviar si devuelve duplicate=true se muestra confirmación al usuario o se impide el envío.

6) Detección difusa (opcional)

Si quieres detectar variaciones pequeñas (paráfrasis, cambios de párrafos) añade una comprobación por similitud usando similar_text o levenshtein. Esto es más caro computacionalmente úsalo solo cuando el conjunto de posts es razonable, o en background.

= (float) threshold
}
?>

Uso recomendado: primero comprobar por hash (rápido) si no hay coincidencia exacta, correr comparaciones difusas solo contra un subgrupo relevante (por ejemplo posts del último año o posts con categorías compartidas).

Consideraciones de rendimiento

Migración y detección masiva de duplicados existentes

Para proyectos donde ya hay miles de posts, calcule los hashes en lote usando WP-CLI o un script que recorra posts y ejecute update_post_meta. Ejemplo conceptual (WP-CLI):

 post, posts_per_page => -1, fields => ids ) )
foreach ( posts as id ) {
    p = get_post( id )
    hash = mi_normalizar_y_hash_post( p->post_title, p->post_content )
    update_post_meta( id, _mi_content_hash, hash )
}
?>

Después de popular postmeta se pueden detectar duplicados con una simple consulta SQL sobre wp_postmeta agrupando por meta_value.

Seguridad y buenas prácticas

Pruebas y casos de uso

  1. Crear un post exacto y verificar que el siguiente intento queda en borrador y muestra aviso.
  2. Probar con pequeñas variaciones (espacios, mayúsculas) — deben considerarse iguales por la normalización.
  3. Comprobar el flujo front-end con AJAX: que impida enviar o avise antes.
  4. Probar rendimiento en un sitio con muchos posts medir consultas y latencias.

Errores comunes y soluciones

Conclusión

La verificación previa contra contenido duplicado en WordPress es alcanzable con una combinación de hash normalizado, hooks nativos (wp_insert_post_data y save_post) y, opcionalmente, comprobaciones difusas y AJAX en front-end. Este enfoque reduce riesgos SEO y mejora la calidad del contenido sin alterar significativamente el flujo de trabajo de los editores. Para sitios con grandes volúmenes de contenido, planifique almacenamiento indexado del hash y procesos de migración batch.

Notas finales

Personalice el conjunto de campos usados para el hash (por ejemplo incluir excerpt, fields personalizados o taxonomías) y decida la acción frente a un duplicado (bloquear, convertir a borrador o solo notificar). Las piezas de código aquí proporcionadas son plantillas pensadas para adaptarse a su entorno, permisos y políticas de publicación.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *