Como añadir autocompletado al buscador con datalist y JS en WordPress

Contents

Introducción

En este tutorial detallado veremos cómo añadir autocompletado al buscador de un sitio WordPress utilizando la etiqueta HTML5 datalist combinada con JavaScript. Presentaré dos enfoques: (1) llenado del datalist desde PHP en el servidor (opción simple y sin AJAX) y (2) llenado dinámico mediante una petición al REST API de WordPress (en tiempo real, escalable). También cubro cómo encolar scripts en el theme, seguridad, accesibilidad, rendimiento y problemas comunes.

Requisitos y consideraciones previas

  • Conocimientos básicos de cómo editar el tema (preferible usando un child theme).
  • WordPress moderno (4.7 para REST API, aunque se recomienda versiones recientes).
  • Acceso para editar functions.php, crear searchform.php en el tema y añadir archivos JS/CSS.
  • Comprender limitaciones del elemento datalist: es simple y útil, pero no es un control ARIA completo para necesidades complejas puede requerirse un widget accesible extra.

1) Método básico: renderizar opciones en el servidor (searchform.php)

Este método es el más sencillo: al generar el formulario de búsqueda incluimos un elemento datalist con options creadas en PHP a partir de resultados (por ejemplo, títulos de entradas recientes). Es ideal si la lista puede ser estática o limitada en tamaño.

Ejemplo de searchform.php (colócalo en la raíz del theme o child theme):

 post,
  posts_per_page => max,
  post_status    => publish,
  fields         => ids,
  orderby        => date,
)
posts = new WP_Query( query_args )
?>

Ventajas de este enfoque:

  • Fácil de implementar.
  • No requiere JavaScript adicional para que funcione el autocompletado básico.
  • Buena para sitios con pocas entradas o cuando las sugerencias pueden ser generadas de forma segura en cada carga de página.

Limitaciones:

  • Lista estática en la carga: no es sensible al texto que el usuario escribe en tiempo real.
  • Problemas de rendimiento si se devuelven cientos o miles de opciones.
  • No ideal para búsqueda tipo “live suggestions”.

2) Método dinámico: autocompletado en tiempo real usando REST API y JavaScript

Este enfoque utiliza un endpoint REST personalizado que devuelve sugerencias según lo que el usuario escriba, y JavaScript para poblar el elemento datalist en tiempo real. Es escalable, reduce el tamaño inicial del HTML y permite búsquedas parciales en todo el contenido.

2.1 Encolar el script y registrar REST route

Añade al functions.php del tema (o un plugin personalizado) el siguiente código para encolar el archivo JS y crear un endpoint REST simple que devuelva resultados en JSON.

 esc_url_raw( rest_url( /custom/v1/search ) ),
    nonce    => wp_create_nonce( wp_rest ),
  ) )
}
add_action( wp_enqueue_scripts, theme_enqueue_search_autocomplete )

// Registrar endpoint REST para sugerencias
add_action( rest_api_init, function() {
  register_rest_route( custom/v1, /search, array(
    methods  => GET,
    callback => custom_search_suggestions,
    permission_callback => __return_true,
  ) )
} )

function custom_search_suggestions( WP_REST_Request request ) {
  q = sanitize_text_field( request->get_param( q ) )
  max = 20
  if ( empty( q ) ) {
    return rest_ensure_response( array() )
  }
  args = array(
    s                      => q,
    post_status            => publish,
    posts_per_page         => max,
    no_found_rows          => true,
    update_post_term_cache => false,
  )
  query = new WP_Query( args )
  results = array()
  if ( query->have_posts() ) {
    foreach ( query->posts as post ) {
      results[] = array(
        id        => post->ID,
        title     => get_the_title( post->ID ),
        permalink => get_permalink( post->ID ),
      )
    }
  }
  return rest_ensure_response( results )
}
?>

2.2 JavaScript: obtener sugerencias y poblar el datalist

Ejemplo de archivo js/search-autocomplete.js. Implementa debounce, abort controller para peticiones en vuelo y rellena el datalist con los títulos devueltos.

(function() {
  const input = document.querySelector(input[list=search-suggestions])
  const datalistId = search-suggestions
  const endpoint = window.searchAutocompleteData  window.searchAutocompleteData.rest_url ? window.searchAutocompleteData.rest_url : /wp-json/custom/v1/search
  let controller
  let debounceTimer

  function debounce(fn, delay) {
    return function(...args) {
      clearTimeout(debounceTimer)
      debounceTimer = setTimeout(() => fn.apply(this, args), delay)
    }
  }

  function clearOptions() {
    const dl = document.getElementById(datalistId)
    if (!dl) return
    dl.innerHTML = 
  }

  async function fetchSuggestions(q) {
    if (!q) {
      clearOptions()
      return
    }
    if (controller) controller.abort()
    controller = new AbortController()
    const url = endpoint   ?q=   encodeURIComponent(q)
    try {
      const res = await fetch(url, {
        method: GET,
        headers: {
          X-WP-Nonce: window.searchAutocompleteData ? window.searchAutocompleteData.nonce : 
        },
        signal: controller.signal,
        credentials: same-origin
      })
      if (!res.ok) return
      const data = await res.json()
      populateDatalist(data)
    } catch (e) {
      // petición abortada o fallo silencioso
    }
  }

  function populateDatalist(items) {
    const dl = document.getElementById(datalistId)
    if (!dl) return
    dl.innerHTML = 
    items.forEach(item => {
      const option = document.createElement(option)
      option.value = item.title  
      dl.appendChild(option)
    })
  }

  if (input) {
    input.addEventListener(input, debounce(function(e) {
      const q = e.target.value.trim()
      fetchSuggestions(q)
    }, 250))
  }
})()

2.3 CSS mínimo (opcional)

/ Estilos mínimos para el formulario /
.search-form { display: flex gap: .5rem align-items: center }
.search-form input[type=search] { padding: .5rem min-width: 220px }

3) Accesibilidad y mejores prácticas

  • Etiquetas visibles y lecturas de pantalla: Mantén un label accesible o una span con clase screen-reader-text para describir el campo.
  • ARIA: El elemento datalist no expone automáticamente todos los roles ARIA que algunos lectores de pantalla esperan. Para mayor accesibilidad, asegúrate de que el campo tenga atributos como aria-controls apuntando al id del datalist, aunque el soporte varía entre lectores.
  • Foco y teclado: Las opciones del datalist deben poder seleccionarse con teclado (esto depende del soporte del navegador).
  • Fallback: En navegadores que no soportan datalist correctamente (algunos Safari antiguos), considera cargar una librería polyfill o proporcionar un autocompletado alternativo basado en una lista desplegable creada con HTML/JS accesible.

4) Seguridad, rendimiento y límites prácticos

  • Saneamiento: Sanitiza cualquier parámetro recibido (p. ej. sanitize_text_field) y escapa las salidas (esc_attr, esc_html) en PHP.
  • Nonce/Credentials: Para consultas REST que requieran autenticación o protección adicional, utiliza nonces. En muchos casos de sugerencias públicas no es estrictamente necesario, pero añadir el encabezado X-WP-Nonce y verificarlo puede ayudar si el endpoint hace operaciones más sensibles.
  • Limitar resultados: No devuelvas cientos de opciones. Limita a 10–50 registros según el caso. Para sitios grandes, utiliza índices, reglas de búsqueda más específicas o motor de búsqueda avanzado (Elastic, algolia, etc.).
  • Cache: Implementa cache si la misma consulta se realiza con frecuencia (transients, WP Object Cache o cache a nivel HTTP).
  • Protección contra abuso: Implementa rate-limiting si el endpoint puede ser abusado para scraping o carga alta.

5) Compatibilidad de navegadores y polyfills

  • El elemento datalist está soportado por la mayoría de navegadores modernos, pero ha tenido inconsistencias históricas (comportamiento en Safari, selección con teclado, estilo de las opciones).
  • Si necesitas soporte consistente, considera usar un componente JS de autocompletado accesible (Awesomplete, Autocomplete.js, etc.) o un polyfill para datalist.
  • Enlace a una implementación útil (libro de referencia o polyfill): https://github.com/LeaVerou/datalist-polyfill

6) Sugerencias y casos avanzados

  • Agregar tipos de sugerencias (categorías, etiquetas, productos) devolviendo objetos con type y mostrar prefijos en el texto de la opción.
  • Autocompletar por taxonomías: consulta términos en lugar de posts si tiene sentido.
  • Mejorar relevancia: ordenar por coincidencia (títulos que empiezan por la cadena primero) en lugar de ordenar solo por fecha.
  • Implementar selección por teclado y redirección al pulsar Enter cuando el valor coincide exactamente con una sugerencia (p. ej. redirigir a la URL devuelta por el endpoint).

7) Pruebas y resolución de problemas comunes

  1. Si no ves sugerencias: comprobar que el datalist tiene el mismo id que el atributo list del input.
  2. Si el fetch devuelve 401/403: revisar cabeceras X-WP-Nonce y permisos para rutas públicas asegúrate de que permission_callback permita acceso.
  3. Si aparecen caracteres raros: siempre usar las funciones de escape y sanitización de WP (esc_attr, esc_html, sanitize_text_field).
  4. Si la app se vuelve lenta con muchas peticiones: implementar debounce (ej. 200–300 ms), abort controller para cancelar peticiones previas y cachear resultados frecuentes.
  5. Si la selección con teclado no funciona uniformemente: verificar compatibilidad del navegador con datalist y considerar polyfill o componente personalizado.

Resumen

Utilizar datalist con JavaScript y WordPress permite añadir autocompletado de forma simple (server-side) o potente (REST API JS). Para sitios pequeños el renderizado directo en searchform.php es suficiente para búsquedas en tiempo real en sitios grandes la combinación REST API debounce limitación de resultados es la mejor práctica. No olvides la accesibilidad, saneamiento de datos y límites de rendimiento.

Fragmentos rápidos

En resumen, los archivos clave que crearás/editarás son:

  • searchform.php — formulario de búsqueda con input y datalist.
  • functions.php — encolar JS y registrar el endpoint REST.
  • js/search-autocomplete.js — lógica cliente para pedir sugerencias y poblar el datalist.

Implementando lo anterior tendrás un autocompletado funcional, seguro y escalable para el buscador de WordPress.



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 *