Envío de formularios sin recargar la página: implementación de AJAX en WordPress
Publicado: 2022-03-10Si alguna vez ha querido enviar un formulario sin volver a cargar la página, proporcione una función de búsqueda anticipada que solicite al usuario sugerencias a medida que escribe o guarde automáticamente los documentos, entonces lo que necesita es AJAX (también conocido como XHR ). Se envía una solicitud detrás de escena al servidor y se devuelven datos a su formulario. Cada vez que vea una animación del cargador después de haber realizado alguna acción en la página, es probable que se envíe una solicitud AJAX al servidor.
En este artículo, lo guiaré a través de todo el proceso de creación y manejo de llamadas AJAX. Aprenderá no solo cómo hacer una llamada AJAX, sino también cómo hacerlo de la mejor manera usando las funciones que WordPress ofrece a los desarrolladores desde el primer momento. Crearemos un complemento simple que permitirá a los lectores enviar un informe al administrador con información sobre cualquier error que puedan detectar en su sitio web.

Al final del artículo, puede descargar el ejemplo de trabajo y examinar el código completo.
¡Vamos a profundizar en!
AJAX
“Sin recargar la página” es la frase clave aquí. AJAX significa JavaScript asíncrono y XML porque, inicialmente, se supone que los datos devueltos por el servidor están en XML. Sin embargo, es más fácil enviarlos en JSON, que a JavaScript le gusta más.
Vamos a utilizar AJAX para enviar un correo electrónico. No puede hacerlo desde el front-end, por lo que debe llamar al back-end. Por lo general, enviamos una solicitud POST al servidor, la manejamos y redirigimos al usuario a la página con el formulario. En esta iteración, no queremos volver a cargar la página. En cambio, estamos llamando al backend directamente donde vamos a capturar los datos del formulario con JavaScript, luego enviamos una solicitud asíncrona al servidor para manejar la respuesta.
Hay tres cosas que WordPress AJAX necesita para funcionar, cinco de ellas para funcionar bien . Estos son:
- Objeto para la acción AJAX
- secuencia de comandos JavaScript
- Acción de WordPress
- Proteccion
- Manejo de errores
Echemos un vistazo más de cerca a cada uno de ellos.
Objeto
Nuestro objeto es la forma. Esto es lo que tenemos que manejar con JavaScript. Comencé creando un archivo con el encabezado que necesita el complemento de WordPress y poniendo un objeto vacío dentro. Al final, estoy creando una nueva instancia de la clase del complemento.
<?php /* Plugin Name: Report a bug Description: Allow your visitors to report a bug in your articles Author: Jakub Mikita Author URI: https://underdev.it Version: 1.0 License: GPL2 Text Domain: reportabug */ class Report_a_bug { } new Report_a_bug();
Aunque estoy usando algo de programación orientada a objetos aquí, no vamos a utilizar ninguna práctica avanzada. El código funcionaría igual de bien cuando se escribiera procedimentalmente con funciones separadas. Pero los objetos dentro de los complementos de WordPress tienen una ventaja: no es necesario que prefije sus funciones, solo el nombre de la clase debe ser único.
Mostremos nuestro formulario a los usuarios. Vamos a conectarnos al filtro the_content
e incrustar el formulario al final de cada publicación. En el constructor de clase, agregué el filtro:
public function __construct() { add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 ); }
Y creó un método de devolución de llamada con formulario HTML:
public function report_button( $content ) { // display button only on posts if ( ! is_single() ) { return $content; } $content .= '<div class="report-a-bug"> <button class="show-form" data-post_>' . __( 'Report a bug', 'reportabug' ) . '</button> <textarea class="report-a-bug-message" placeholder="' . __( 'Describe what\'s wrong...', 'reportabug' ) . '"></textarea> <p class="report-a-bug-response"></p> </div>'; return $content; }
El formulario tiene todo el marcado necesario:
- Un botón para mostrar el formulario y enviar el mensaje;
-
textarea
; - Contenedor para la respuesta (vamos a usar esto más adelante).
El botón tiene el atributo data-post_id
que almacena el ID de la publicación actual. Tomaremos esto en JavaScript para identificar el artículo.
Solo necesitamos algunos estilos básicos, así que registremos nuestra propia hoja de estilo con la acción wp_enqueue_scripts
y la devolución de llamada correspondiente:
public function __construct() { add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 ); add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) ); } function scripts() { wp_enqueue_style( 'report-a-bug', plugin_dir_url( __FILE__ ) . 'css/style.css' ); }
La hoja de estilo en sí es muy simple. Queremos arreglar el diseño.
.report-a-bug-message { display: none; margin-top: 1em; } .report-a-bug-response { margin-top: 1em; }
Así es como se ve el botón:

Texto
Ya tenemos nuestro objeto listo para ponerle algo de vida. En lugar de hacerlo en JavaScript simple, usaremos jQuery, que WordPress carga de forma predeterminada en cada página.
En el método de scripts existente, agregaré el archivo JS usando la función wp_enqueue_script
.
function scripts() { wp_enqueue_style( 'report-a-bug', plugin_dir_url( __FILE__ ) . 'css/style.css' ); wp_enqueue_script( 'report-a-bug', plugin_dir_url( __FILE__ ) . 'js/scripts.js', array( 'jquery' ), null, true ); // set variables for script wp_localize_script( 'report-a-bug', 'settings', array( 'send_label' => __( 'Send report', 'reportabug' ) ) ); }
También estoy usando la función wp_localize_script
para pasar la etiqueta del botón traducida a JS. No tenemos ninguna función gettext
en JavaScript, así que tenemos que hacerlo aquí. Esta función creará el objeto de configuración al que se puede acceder directamente desde nuestro script.
En nuestro script, vamos a escuchar el clic de un botón. Una vez que eso suceda, mostraremos el área de texto y textarea
la clase de botón para escuchar el segundo clic que envía el formulario.
( function( $ ) { $( document ).ready( function() { $( '.report-a-bug' ).on( 'click', '.show-form', function( event ) { // change label and switch class $( this ).text( settings.send_label ).removeClass( 'show-form' ).addClass( 'send-report' ); // show textarea $( '.report-a-bug-message' ).slideDown( 'slow' ); }) }); })( jQuery );
Aquí está el progreso actual:

textarea
desplegable del área de texto al hacer clic¡Es el mejor momento para crear la solicitud AJAX!
Solicitudes AJAX a WordPress
Para enviar una solicitud AJAX, solo necesita un único parámetro: la URL solicitada. WordPress tiene el archivo especial para AJAX, por lo que no tenemos que crear uno propio. Es /wp-admin/admin-ajax.php
.
Siempre que estemos en el área wp-admin
, esta URL de archivo está disponible en JS en la variable ajaxurl
. En el front-end, tenemos que pasar esta variable por nuestra cuenta. Afortunadamente, ya usamos la función wp_localize_script
, por lo que podemos agregarle otra clave:
wp_localize_script( 'report-a-bug', 'settings', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'send_label' => __( 'Send report', 'reportabug' ) ) );
Hemos preparado todas las variables, así que vamos a crear la llamada AJAX. Lo enviaremos una vez que el usuario haga clic en el botón por segunda vez.
$( '.report-a-bug' ).on( 'click', '.send-report', function( event ) { var $button = $( this ); $button.width( $button.width() ).text('...'); // set ajax data var data = { 'action' : 'send_bug_report', 'post_id': $button.data( 'post_id' ), 'report' : $( '.report-a-bug-message' ).val() }; $.post( settings.ajaxurl, data, function( response ) { console.log( 'ok' ); } ); } );
Estamos escuchando un clic en la clase que activamos el botón antes.
Como puede ver, estoy cambiando el texto del botón a "..." ¿Por qué? Porque es una buena práctica mostrarle al usuario que algo está sucediendo. Las solicitudes de AJAX dependen del rendimiento del servidor y llevarán algún tiempo. Quizás 30 ms, pero quizás también 3 segundos. Si después de hacer clic en el botón parece no haber ningún efecto, lo más probable es que se haga clic en el botón por segunda vez. Esto duplicaría la solicitud porque, como ahora sabe, estos son asincrónicos.
A continuación, estoy creando el objeto data
. Esto contiene todas las variables que se enviarán a la devolución de llamada del servidor. El archivo WordPress admin-ajax.php
requiere la propiedad de acción. Esto tiene que ser único a menos que desee que el otro complemento maneje sus solicitudes. El resto de los parámetros es opcional. Estoy enviando el ID de la publicación y el mensaje de informe desde textarea
.

Entonces estamos llamando al método $.post
. Luego, lo adivinaste; está enviando la solicitud POST. Es un método abreviado, pero también puede usar el método $.ajax
, que tiene más opciones. Como primer parámetro, tenemos que pasar la URL de nuestro archivo de controlador, luego los parámetros y luego la función de devolución de llamada exitosa. Este es el lugar donde estamos manejando la respuesta. Por ahora, solo estamos enviando el mensaje simple a la consola del navegador.

Estamos listos para manejar la solicitud en el back-end.
Acción de WordPress
Quizás se pregunte cómo nos conectamos con admin-ajax.php . ¡Con acción, por supuesto! WordPress tiene dos tipos de acciones:
wp_ajax_nopriv_{$action} wp_ajax_{$action}
Donde está $action
, el nombre de la acción se pasa en los parámetros AJAX. Es send_bug_report
en nuestro caso.
La primera de estas acciones se ejecutará solo para usuarios que no hayan iniciado sesión. El segundo solo para usuarios registrados. Entonces, si desea que la solicitud se maneje para ambos, debe definir ambos. Esto es lo que he hecho en el constructor de la clase:
public function __construct() { add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 ); add_action( 'wp_enqueue_scripts', array( $this, 'scripts' ) ); add_action( 'wp_ajax_nopriv_send_bug_report', array( $this, 'send_bug_report' ) ); add_action( 'wp_ajax_send_bug_report', array( $this, 'send_bug_report' ) ); }
En la devolución de llamada, solo obtengo el título de la publicación y envío el correo electrónico:
function send_bug_report() { $data = $_POST; $post_title = get_the_title( intval( $data['post_id'] ) ); wp_mail( '[email protected]', 'Bug report in post: ' . $post_title, $data['report'] ); wp_send_json_success( __( 'Thanks for reporting!', 'reportabug' ) ); }
La parte más importante en términos de manejo de AJAX en WordPress es la última función: wp_send_json_success
, que imprime la salida codificada en JSON y muere. Todo lo que necesitamos para obtener la respuesta con la devolución de llamada exitosa de AJAX. También tiene un hermano gemelo, wp_send_json_error
, pero llegaremos a esa parte más adelante.
El objeto de estas funciones tiene dos propiedades:
- éxito
Es un booleano y depende de si lo llamas función de éxito o error. - datos
Si proporciona el parámetro para la función.
Eso es todo desde el lado del back-end. Manejemos la respuesta en JS.
Vamos a eliminar el botón y el área de texto y mostrar un mensaje devuelto por el servidor en el contenedor que preparamos antes:
$.post(settings.ajaxurl, data, function(response) { // remove button and textarea $button.remove(); $('.report-a-bug-message').remove(); // display success message $('.report-a-bug-response').html( response.data ); });
¡Y eso es! ¡Tenemos la llamada AJAX en funcionamiento! Pero no te detengas allí. Nuestra solicitud no es segura y ciertamente no es fácil de usar. Tenemos que asegurarnos de que la solicitud se ejecute solo cuando sea necesario.
Proteccion
Mientras tanto
El nonce es un "número usado una vez". Es un hash corto creado a partir de una cadena de entrada. Podemos usarlo para validar la solicitud, si realmente ha sido realizada por WordPress y nadie la falsifica.
Vamos a utilizar otro atributo de datos para el botón:
$nonce = wp_create_nonce( 'report_a_bug_' . get_the_ID() ); $content .= '<div class="report-a-bug"> <button class="show-form" data-nonce="' . $nonce . '" data-post_>' . __( 'Report a bug', 'reportabug' ) . '</button> <textarea class="report-a-bug-message" placeholder="' . __( 'Describe what\'s wrong...', 'reportabug' ) . '"></textarea> <p class="report-a-bug-response"></p> </div>';
Como puede ver, estoy agregando la ID de la publicación a la cadena de entrada. Tendremos este ID disponible en las propiedades de solicitud de AJAX, por lo que es más seguro.
Ahora tenemos que agregar el nonce a las propiedades de AJAX:
// set ajax data var data = { 'action' : 'send_bug_report', 'post_id': $button.data('post_id'), 'nonce' : $button.data('nonce'), 'report' : $('.report-a-bug-message').val() };
Ahora lo validaremos en el backend usando la función check_ajax_referer
, que proporciona WordPress:
function send_bug_report() { $data = $_POST; // check the nonce if ( check_ajax_referer( 'report_a_bug_' . $data['post_id'], 'nonce', false ) == false ) { wp_send_json_error(); } $post_title = get_the_title( intval( $data['post_id'] ) ); wp_mail( '[email protected]', 'Bug report in post: ' . $post_title, sanitize_text_field( $data['report'] ) ); wp_send_json_success( __( 'Thanks for reporting!', 'reportabug' ) ); }
Para validar la solicitud, debemos regenerar la cadena de entrada, por lo que estoy usando la clave post_id
enviada desde AJAX. El segundo parámetro es la clave en la $_REQUEST array
. Third controla el wp_die
automatizado si nonce no coincide.
No quiero que se muera solo. En cambio, estoy capturando el resultado de esta función y enviando un error JSON en un objeto agradable.
También puede notar el uso de la función sanitize_text_field
en el parámetro del mensaje de correo electrónico. Esto es solo para asegurarse de que el usuario no envíe scripts o HTML dañinos.
Por último, debemos envolver la devolución de llamada exitosa de AJAX en JS en la declaración if para verificar si la solicitud fue exitosa:
$.post(settings.ajaxurl, data, function(response) { if ( response.success == true ) { // remove button and textarea $button.remove(); $('.report-a-bug-message').remove(); // display success message $('.report-a-bug-response').html( response.data ); } });
Protección de botones
Sabe que el usuario puede hacer clic en el botón por segunda vez, antes de que AJAX finalice la llamada. Pero hay un truco simple que bloqueará el segundo clic: deshabilitar el botón. Entonces, después del clic, lo bloquearé y lo desbloquearé después de recibir la respuesta:
$('.report-a-bug').on('click', '.send-report', function(event) { var $button = $(this); $button.width( $button.width() ).text('...').prop('disabled', true); // set ajax data var data = {...}; $.post(settings.ajaxurl, data, function(response) { if ( response.success == true ) {...} // enable button $button.prop('disabled', false); }); });
Manejo de errores
Validación
¿Qué sucede si el usuario intenta enviar un mensaje vacío? No quiero que me molesten con esos correos electrónicos. Bloqueemos estos intentos con técnicas de validación.
En JS, voy a agregar una validación simple para mostrarle al usuario que algo salió mal. Si el mensaje está vacío, el usuario verá el borde rojo alrededor del área de texto. Si hay un mensaje presente allí, estamos restaurando el borde neutral:
$('.report-a-bug').on('click', '.send-report', function(event) { var $button = $(this); // check if message is not empty if ( $( '.report-a-bug-message' ).val().length === 0 ) { $( '.report-a-bug-message' ).css( 'border', '1px solid red' ); return false; } else { $( '.report-a-bug-message' ).css( 'border', '1px solid rgba(51, 51, 51, 0.1)' ); } // ... ajax });
Comprobación de errores en la acción de WordPress
También podemos tener un problema con el envío del correo electrónico. Si no verificamos el resultado de la función wp_mail
, el usuario recibirá un mensaje de éxito aunque no se haya enviado ningún correo electrónico.
Manejemos esto:
function send_bug_report() { $data = $_POST; // check the nonce if ( check_ajax_referer( 'report_a_bug_' . $data['post_id'], 'nonce', false ) == false ) { wp_send_json_error(); } $post_title = get_the_title( intval( $data['post_id'] ) ); $result = wp_mail( '[email protected]', 'Bug report in post: ' . $post_title, sanitize_text_field( $data['report'] ) ); if ( $result == false ) { wp_send_json_success( __( 'Thanks for reporting!', 'reportabug' ) ); } else { wp_send_json_error(); } }
Como puede ver, hemos usado la función wp_send_json_error
dos veces, pero no es necesario mostrar mensajes únicos para los usuarios. En su lugar, pasando la descripción exacta del error, agregaré otra clave a nuestro objeto de configuración de secuencia de comandos que cubrirá ambos errores:
// set variables for script wp_localize_script( 'report-a-bug', 'settings', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'send_label' => __( 'Send report', 'reportabug' ), 'error' => __( 'Sorry, something went wrong. Please try again', 'reportabug' ) ) );
Todo lo que queda por hacer es mostrar el error al usuario:
$.post( settings.ajaxurl, data, function( response ) { if ( response.success == true ) { // remove button and textarea $button.remove(); $( '.report-a-bug-message' ).remove(); // display success message $( '.report-a-bug-response' ).html( response.data ); } else { // display error message $( '.report-a-bug-response' ).html( settings.error ); } // enable button and revert label $button.text( settings.send_label ).prop( 'disabled', false ); } );
Ejemplo completo
¡Lo hicimos! Se ha realizado nuestra solicitud AJAX; está bien protegido y es fácil de usar. Esto es lo que un usuario va a ver en caso de cualquier error:

A continuación puede descargar el complemento completo y consultar las guías de usuario:
- Descarga el complemento en Github
- Descarga el complemento en Wordpress.org
- Ir a las guías de usuario
Espero que esto le brinde una buena base para sus propias soluciones "sin actualizar la página". Puede hacer esto en todos los formularios de su sitio web. También es una excelente manera de optimizar cualquier parte pesada del sitio web que no tenga que cargarse de inmediato, como una gran lista de productos en un menú desplegable. Puede cargarlos a través de AJAX justo después de hacer clic en el menú desplegable, es así de simple.
Las posibilidades son casi ilimitadas. ¡Déjame saber en los comentarios cuáles son tus ideas!