Como interceptar 404 y sugerir contenidos relacionados con PHP en WordPress

Contents

Introducción

En este tutorial detallado aprenderás a interceptar errores 404 en WordPress y a ofrecer sugerencias de contenido relacionadas mediante PHP. El objetivo es mejorar la experiencia del usuario, reducir tasas de rebote y recuperar tráfico potencial que de otro modo se perdería. Verás varias aproximaciones —desde la más simple y segura hasta implementaciones más avanzadas con cache, búsqueda por similitud y registro de URLs 404 para análisis— junto con fragmentos de código listos para integrar en tu tema o plugin.

Conceptos clave y buenas prácticas

  • Preservar el código de estado 404: Aun mostrando sugerencias, el recurso no existe y el servidor debe devolver el código de estado 404 para no perjudicar al SEO.
  • No redirigir automáticamente al home: Las redirecciones masivas a la página principal confunden a usuarios y motores de búsqueda.
  • Saneamiento y seguridad: Siempre sanitiza y prepara consultas a la base de datos y datos de entrada.
  • Cachear resultados: Generar sugerencias puede implicar consultas costosas usa transients o un sistema de cache para mejorar rendimiento.
  • Medir y aprender: Registrar los 404 frecuentes te permitirá crear redirecciones o contenidos nuevos específicos.

Dónde interceptar 404 en WordPress

Hay varias maneras de detectar un 404:

  1. Plantilla 404 de tu tema: el archivo 404.php es el lugar natural para mostrar sugerencias.
  2. Hook template_redirect: detecta is_404() y actúa antes de renderizar plantilla.
  3. Hook pre_handle_404 o send_headers: opciones más avanzadas si necesitas controlar cabeceras y flujo.

Ejemplo simple: añadir sugerencias en 404.php

La solución más directa: en tu 404.php generar una búsqueda basada en la URL solicitada y mostrar resultados.

lt?php
// 404.php (fragmento)
// 1) Asegúrate de que WordPress marque el estado 404
status_header(404)

// 2) Obtener la ruta solicitada (sin dominio ni query string)
requested_path = trim( parse_url( _SERVER[REQUEST_URI], PHP_URL_PATH ), / )

// 3) Preparar cadena de búsqueda (reemplaza símbolos por espacios)
search_terms = preg_replace(/[/-_] /,  , requested_path)
search_terms = urldecode( search_terms )
search_terms = trim( search_terms )

// 4) Ejecutar búsqueda simple con WP_Query
search_query = new WP_Query( array(
  post_type => array(post,page),
  posts_per_page => 6,
  s => search_terms,
  post_status => publish,
) )

// 5) Mostrar sugerencias si hay resultados
if ( search_query-gthave_posts() ) {
  echo lth3gtQuizá te interesen estos contenidos:lt/h3gt
  echo ltulgt
  while ( search_query-gthave_posts() ) {
    search_query-gtthe_post()
    echo ltligtlta href=.get_permalink().. gt.get_the_title().lt/agtlt/ligt
  }
  echo lt/ulgt
  wp_reset_postdata()
} else {
  echo ltpgtNo se han encontrado sugerencias automáticas.lt/pgt
}
?gt

Métodos para encontrar contenidos relacionados

Dependiendo del sitio y su estructura, puedes usar una o varias técnicas combinadas:

  • Búsqueda simple (s) con WP_Query: rápida y sencilla funciona bien cuando el slug o la URL contienen palabras clave útiles.
  • Coincidencia por taxonomías (categorías/etiquetas): extraer términos del slug y buscar posts que compartan esas taxonomías.
  • Fulltext/FTS en MySQL: más precisa para grandes cantidades de contenido, pero requiere índices FULLTEXT y puede necesitar permisos.
  • Ranking por distancia de Levenshtein o similitud: útil para errores tipográficos se obtiene una lista de candidatos y luego se ordena por similitud.

Ejemplo avanzado: combinar taxonomías búsqueda ranking por similitud

Este ejemplo generará candidatos por búsqueda general, buscará coincidencias por etiquetas/categorías y luego ordenará por similitud del título (levenshtein) para sugerir resultados más relevantes.

lt?php
function get_suggestions_for_404( requested_path, limit = 6 ) {
  global wpdb

  requested_path = trim( requested_path, /  )
  search = preg_replace(/[/-_] /,  , requested_path )
  search = sanitize_text_field( urldecode( search ) )

  // 1) Buscar candidatos por texto
  candidates = new WP_Query( array(
    post_type => array(post,page),
    post_status => publish,
    s => search,
    posts_per_page => 20, // obtener más para luego ordenar
  ) )

  results = array()

  if ( candidates->have_posts() ) {
    while ( candidates->have_posts() ) {
      candidates->the_post()
      title = get_the_title()
      permalink = get_permalink()
      // 2) Calcular distancia de Levenshtein entre título y ruta (o palabras clave)
      dist = levenshtein( strtolower( search ), strtolower( title ) )
      results[] = array(
        ID => get_the_ID(),
        title => title,
        permalink => permalink,
        distance => dist,
      )
    }
    wp_reset_postdata()
  }

  // 3) Ordenar por menor distancia (más parecido)
  usort( results, function(a, b) {
    return a[distance] - b[distance]
  } )

  // 4) Devolver los primeros limit elementos
  return array_slice( results, 0, limit )
}

// Ejemplo de uso dentro de 404.php:
requested_path = trim( parse_url( _SERVER[REQUEST_URI], PHP_URL_PATH ), / )
suggestions = get_suggestions_for_404( requested_path, 6 )

if ( ! empty( suggestions ) ) {
  echo lth3gtContenido relacionado sugerido:lt/h3gt
  echo ltulgt
  foreach ( suggestions as s ) {
    echo ltligtlta href= . esc_url( s[permalink] ) . gt . esc_html( s[title] ) . lt/agtlt/ligt
  }
  echo lt/ulgt
}
?gt

Optimización y cache

Generar sugerencias puede implicar búsquedas pesadas. Usa transients para cachear resultados por URL solicitada. Además, invalidar cache cuando se publiquen contenidos relevantes.

lt?php
function get_cached_404_suggestions( requested_path ) {
  key = 404_sugg_ . md5( requested_path )
  cached = get_transient( key )
  if ( cached !== false ) {
    return cached
  }
  // si no hay cache, generar
  suggestions = get_suggestions_for_404( requested_path, 6 )
  // cache por 1 hora
  set_transient( key, suggestions, HOUR_IN_SECONDS )
  return suggestions
}
?gt

Registro de 404 (logging) para análisis

Registrar las URL 404 más frecuentes te permite identificar patrones y crear redirecciones 301 o contenido nuevo. A continuación un ejemplo de creación de tabla en la activación de un plugin y la función que registra o incrementa el contador.

lt?php
// En el archivo principal del plugin:
register_activation_hook( __FILE__, mi_plugin_create_404_table )

function mi_plugin_create_404_table() {
  global wpdb
  table = wpdb->prefix . 404_logs
  charset_collate = wpdb->get_charset_collate()

  sql = CREATE TABLE table (
    id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    url text NOT NULL,
    referer text NULL,
    ip varchar(100) NULL,
    user_agent text NULL,
    hits int(11) NOT NULL DEFAULT 1,
    last_seen datetime NOT NULL,
    PRIMARY KEY  (id)
  ) charset_collate

  require_once ABSPATH . wp-admin/includes/upgrade.php
  dbDelta( sql )
}

// Función para registrar 404 (llamarla desde template_redirect cuando is_404)
function mi_plugin_log_404() {
  if ( ! is_404() ) {
    return
  }
  global wpdb
  table = wpdb->prefix . 404_logs

  url = esc_url_raw( wp_unslash( _SERVER[REQUEST_URI] ) )
  referer = isset( _SERVER[HTTP_REFERER] ) ? esc_url_raw( wp_unslash( _SERVER[HTTP_REFERER] ) ) : null
  ip = isset( _SERVER[REMOTE_ADDR] ) ? _SERVER[REMOTE_ADDR] : null
  ua = isset( _SERVER[HTTP_USER_AGENT] ) ? sanitize_text_field( wp_unslash( _SERVER[HTTP_USER_AGENT] ) ) : null

  // Intentar actualizar el registro existente
  existing = wpdb->get_row( wpdb->prepare( SELECT id, hits FROM table WHERE url = %s, url ) )

  if ( existing ) {
    wpdb->update(
      table,
      array(
        hits => existing->hits   1,
        last_seen => current_time( mysql ),
      ),
      array( id => existing->id ),
      array( %d, %s ),
      array( %d )
    )
  } else {
    wpdb->insert(
      table,
      array(
        url => url,
        referer => referer,
        ip => ip,
        user_agent => ua,
        hits => 1,
        last_seen => current_time( mysql ),
      ),
      array( %s, %s, %s, %s, %d, %s )
    )
  }
}
// Enganchar al template_redirect
add_action( template_redirect, mi_plugin_log_404, 5 )
?gt

Uso de FULLTEXT y MySQL para sitios grandes

Si tu base de datos tiene índices FULLTEXT en post_title/post_content, puedes usar consultas MATCH…AGAINST para obtener resultados más relevantes y rápidos en colecciones grandes. Asegúrate de añadir índices y probar la compatibilidad con tu versión de MySQL/MariaDB.

-- Ejemplo de índice fulltext (ejecutar en la base de datos)
ALTER TABLE wp_posts ADD FULLTEXT KEY ft_title_content (post_title, post_content)
lt?php
global wpdb
search = texto a buscar // sanear antes
sql = wpdb->prepare(
  SELECT ID, post_title, MATCH(post_title, post_content) AGAINST (%s IN NATURAL LANGUAGE MODE) AS score
   FROM {wpdb->posts}
   WHERE post_status = publish AND post_type IN (post,page)
   AND MATCH(post_title, post_content) AGAINST (%s IN NATURAL LANGUAGE MODE)
   ORDER BY score DESC LIMIT 6,
  search, search
)
rows = wpdb->get_results( sql )
?gt

Consideraciones SEO y de UX

  • Cabecera 404: Mantén status_header(404) para que los buscadores sepan que el recurso no existe.
  • Contenido útil: Ofrece enlaces a páginas relevantes, un buscador interno y enlaces a categorías populares.
  • Redirecciones selectivas: Si detectas una URL muy frecuente que debería mapear a un nuevo recurso, crea una redirección 301 permanente en lugar de mostrar siempre el 404.
  • No indexar páginas 404: Añade meta robots noindex si tu 404 genera URLs accesibles que no deberían indexarse por duplicidad de contenido.

Errores comunes y cómo evitarlos

  • Eliminar el status 404: Evita devolver 200 OK en páginas que no existen suele penalizar al SEO.
  • Buscar en campos no sanitizados: Usa prepare/esc_sql y funciones de saneamiento al hacer consultas directas.
  • Queries pesadas sin cache: Cachea los resultados con transients o con el sistema de object cache para no cargar la DB en cada 404.

Resumen práctico paso a paso

  1. Decide si la lógica irá en 404.php o en un plugin (plugin es preferible para mantener portabilidad).
  2. Obtén la URL solicitada y genera términos de búsqueda razonables (separar rutas, sustituir guiones, decodificar).
  3. Busca candidatos con WP_Query o consultas optimizadas (FULLTEXT) y ordénalos por relevancia.
  4. Cachea los resultados por URL para mejorar rendimiento.
  5. Registra 404 recurrentes para tomar decisiones de redirección o creación de contenido.
  6. Mantén el código de estado 404 y ofrece una experiencia de usuario clara y útil.

Tabla comparativa rápida

Método Ventajas Inconvenientes
Búsqueda s con WP_Query Fácil de implementar, sin DB estructural Menos precisa en grandes sitios, puede ser lenta
FULLTEXT (MySQL) Rápida y precisa con índices Requiere cambios en BD y configuración
Taxonomía coincidencia Muy relevante si la URL refleja categorías/etiquetas Requiere lógica de extracción de términos

Ejemplo final compacto: todo integrado (snippet para functions.php)

lt?php
// Enganchar detección temprana
add_action( template_redirect, mi_404_interceptor, 5 )

function mi_404_interceptor() {
  if ( ! is_404() ) {
    return
  }

  // Marcar cabecera 404
  status_header(404)

  // Obtener ruta
  requested = trim( parse_url( _SERVER[REQUEST_URI], PHP_URL_PATH ), / )

  // Intentar recuperar cache de sugerencias
  cache_key = 404_sugg_ . md5( requested )
  suggestions = get_transient( cache_key )

  if ( suggestions === false ) {
    suggestions = get_suggestions_for_404( requested, 6 ) // función definida antes
    set_transient( cache_key, suggestions, HOUR_IN_SECONDS )
  }

  // Registrar 404 para análisis
  if ( function_exists( mi_plugin_log_404 ) ) {
    mi_plugin_log_404()
  }

  // Si estamos en el flujo de 404.php no hacemos más en plantillas headless podrías inyectar sugerencias.
  // Aquí no redirigimos solo dejamos sugerencias disponibles para la plantilla 404.
  // Las sugerencias pueden almacenarse globalmente para ser leídas en 404.php:
  GLOBALS[mi_404_suggestions] = suggestions
}
?gt

Últimas notas

Implementar sugerencias en páginas 404 mejora la experiencia y puede recuperar tráfico. Empieza por una solución simple y mide resultados: ¿las sugerencias capturan clics? ¿qué URLs aparecen con más frecuencia en tus logs 404? A partir de esos datos, ajusta las reglas de búsqueda, añade redirecciones y crea contenido cuando sea necesario.



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 *