Como cargar comentarios vía AJAX con REST y JS en WordPress

Contents

Introducción

Este tutorial explica paso a paso cómo cargar comentarios en WordPress de forma asíncrona usando la API REST y JavaScript (AJAX). La solución que proponemos crea un endpoint REST personalizado para insertar comentarios (compatible con comentarios para usuarios no autenticados y autenticados), gestiona la seguridad básica, prepara el script cliente y muestra cómo insertar el comentario en el DOM sin recargar la página.

Requisitos

  • WordPress 4.7 (API REST incorporada).
  • Acceso para editar functions.php o crear un plugin simple.
  • Conocimientos básicos de PHP y JavaScript.

Flujo de trabajo

  1. Registrar un endpoint REST personalizado que valide y cree comentarios mediante wp_new_comment.
  2. Encolar y localizar un script JavaScript que capture el envío del formulario y realice un fetch POST al endpoint.
  3. Renderizar el comentario nuevo en el HTML de la página sin recarga, gestionando estados y errores.

1) Endpoint REST en PHP (functions.php o plugin)

Añade este código a functions.php de tu tema hijo o dentro de un plugin. El endpoint estará en /wp-json/my/v1/comment y aceptará POST con los campos mínimos: post, author, author_email, content. El código sanitiza entradas, verifica que los comentarios están abiertos y usa wp_new_comment para insertar el comentario.

 POST,
        callback => my_handle_comment,
        permission_callback => __return_true // permitimos validación dentro del callback
    ))
})

function my_handle_comment( WP_REST_Request request ) {
    params = request->get_json_params()

    post_id = isset(params[post]) ? intval(params[post]) : 0
    if ( ! post_id  ! comments_open( post_id ) ) {
        return new WP_REST_Response( array(
            code => comments_closed,
            message => Comentarios cerrados para este post.
        ), 400 )
    }

    author = isset(params[author]) ? sanitize_text_field( params[author] ) : 
    author_email = isset(params[author_email]) ? sanitize_email( params[author_email] ) : 
    content = isset(params[content]) ? wp_kses_post( params[content] ) : 

    if ( empty( content ) ) {
        return new WP_REST_Response( array(
            code => empty_content,
            message => El comentario está vacío.
        ), 400 )
    }

    // Si el usuario está logueado, podemos recuperar su ID
    user_id = get_current_user_id()
    commentdata = array(
        comment_post_ID => post_id,
        comment_author => author,
        comment_author_email => author_email,
        comment_content => content,
        user_id => user_id
    )

    // Inserta el comentario usando la API de WP
    comment_id = wp_new_comment( commentdata )

    if ( is_wp_error( comment_id ) ) {
        return new WP_REST_Response( array(
            code => insert_failed,
            message => comment_id->get_error_message()
        ), 500 )
    }

    comment = get_comment( comment_id )

    // Preparar respuesta mínima para renderizar en el cliente
    response = array(
        id => comment->comment_ID,
        author => get_comment_author( comment->comment_ID ),
        author_url => get_comment_author_url( comment->comment_ID ),
        date => get_comment_date( , comment->comment_ID ),
        content => apply_filters( comment_text, get_comment_text( comment ), comment ),
        approved => comment->comment_approved
    )

    return new WP_REST_Response( response, 201 )
}
?>

2) Encolar y localizar el script JS

Encola el script que hará el envío por AJAX y pasa datos necesarios (URL base de REST, nonce, ID del post actual). Usa wp_localize_script (o wp_add_inline_script) para exponer esos valores al script cliente.

 esc_url_raw( rest_url() ),
        nonce => wp_create_nonce( wp_rest ),
        post_id => get_the_ID()
    ))
})
?>

3) Formulario HTML

Ejemplo mínimo de formulario de comentarios que puedes colocar en single.php o en la plantilla de comentarios. Este formulario será interceptado por JavaScript.

4) Script JavaScript (cliente)

Ejemplo de my-ajax-comments.js que recoge los datos, llama al endpoint y añade el comentario al DOM. Importante: usar credentials:same-origin para incluir cookies si fuera necesario y enviar X-WP-Nonce si el usuario está autenticado.

(function() {
  // MY_COMMENTS_DATA viene de wp_localize_script
  const restBase = (typeof MY_COMMENTS_DATA !== undefined  MY_COMMENTS_DATA.rest_url) ? MY_COMMENTS_DATA.rest_url : /wp-json/
  const endpoint = restBase   my/v1/comment
  const nonce = (typeof MY_COMMENTS_DATA !== undefined) ? MY_COMMENTS_DATA.nonce : 
  const postID = (typeof MY_COMMENTS_DATA !== undefined) ? MY_COMMENTS_DATA.post_id : null

  const form = document.getElementById(ajax-comment-form)
  const list = document.getElementById(comment-list)
  const submitBtn = document.getElementById(comment-submit)

  function escapeHtml(unsafe) {
    return unsafe.replace(/[<>]/g, function(m) {
      return ({:amp,<:lt,>:gt,:quot,:#039})[m]
    })
  }

  function createCommentHTML(data) {
    // data: {id, author, date, content, approved}
    var li = document.createElement(li)
    li.id = comment-   data.id

    var header = document.createElement(p)
    header.innerHTML =    escapeHtml(data.author)       escapeHtml(data.date)   
    li.appendChild(header)

    var content = document.createElement(div)
    // Si el comentario no está aprobado, mostrar aviso
    if (String(data.approved) !== 1) {
      var pending = document.createElement(em)
      pending.textContent = Tu comentario está pendiente de moderación.
      li.appendChild(pending)
    }

    // Insertamos el HTML seguro retornado por el servidor (ya sanitizado por wp_kses_post)
    content.innerHTML = data.content
    li.appendChild(content)

    return li
  }

  function setLoading(state) {
    if (state) {
      submitBtn.disabled = true
      submitBtn.textContent = Enviando...
    } else {
      submitBtn.disabled = false
      submitBtn.textContent = Enviar comentario
    }
  }

  if (!form) return

  form.addEventListener(submit, function(e) {
    e.preventDefault()

    var author = document.getElementById(author).value.trim()
    var author_email = document.getElementById(email).value.trim()
    var content = document.getElementById(comment).value.trim()

    if (!content) {
      alert(El comentario no puede estar vacío.)
      return
    }

    setLoading(true)

    var payload = {
      post: postID,
      author: author,
      author_email: author_email,
      content: content
    }

    fetch(endpoint, {
      method: POST,
      credentials: same-origin,
      headers: {
        Content-Type: application/json,
        X-WP-Nonce: nonce
      },
      body: JSON.stringify(payload)
    })
    .then(function(response) {
      setLoading(false)
      if (!response.ok) return response.json().then(function(err) { throw err })
      return response.json()
    })
    .then(function(data) {
      // Insertar el comentario en la lista sin recargar
      var li = createCommentHTML(data)
      if (list) list.insertBefore(li, list.firstChild)

      // Limpiar formulario
      form.reset()
    })
    .catch(function(err) {
      console.error(Error al enviar el comentario:, err)
      var msg = (err  err.message) ? err.message : Error desconocido
      alert(No se pudo enviar el comentario:    msg)
    })
  })
})()

5) Seguridad y validaciones adicionales

  • Sanitización: En el backend usamos sanitize_text_field, sanitize_email y wp_kses_post para el contenido. Ajusta las etiquetas permitidas si lo necesitas.
  • Nonce: Enviamos X-WP-Nonce para usuarios autenticados para usuarios no autenticados el endpoint permite insertar comentarios si comments_open es true. Si se necesita más seguridad (antispam), añade verificación adicional.
  • Spam: Integrar Akismet, reCAPTCHA o medidas personalizadas. Se puede validar reCAPTCHA en el servidor antes de insertar el comentario.
  • Moderación: wp_new_comment aplica las reglas de moderación configuradas en WordPress. El campo comment_approved depende de la configuración de la instalación.

6) Consideraciones de accesibilidad y UX

  • Deshabilita el botón mientras se envía para evitar envíos duplicados.
  • Proporciona mensajes claros (pendiente de moderación, error, éxito).
  • Añade etiquetas aria-live si quieres que los lectores de pantalla informen de nuevos mensajes o errores.

7) Casos especiales y extensiones

  • Usuarios logueados: Puedes auto-rellenar nombre/email desde current_user y omitir esos campos en el formulario.
  • Responder a un comentario: Añade un campo parent al payload y pásalo a wp_new_comment para establecer la jerarquía.
  • Renderizado avanzado: Si necesitas el mismo HTML que renderiza tu tema, puedes devolver desde el endpoint un fragmento HTML generado con get_comment_text y plantillas, o usar renderers personalizados en PHP.

8) Depuración

  1. Revisa la consola del navegador para errores CORS o de fetch.
  2. Habilita WP_DEBUG para capturar errores PHP del endpoint.
  3. Verifica las respuestas JSON del endpoint (códigos HTTP y mensajes).

Conclusión

Con este enfoque tienes un flujo completo para enviar comentarios por AJAX usando la REST API de WordPress: un endpoint controlado por PHP, un script cliente que realiza la petición y actualiza la UI y consideraciones de seguridad y acceso. A partir de aquí puedes integrar antispam, mejorar el renderizado del comentario y adaptar la UX a tus necesidades.



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 *