¿Cuál es la mejor manera de finalizar una solicitud AJAX de WordPress y por qué?

24 dic 2016, 14:18:20
Vistas: 21.7K
Votos: 24

Considerando las solicitudes AJAX regulares de WordPress como estas:

add_action( 'wp_ajax_merrychristmas_happynewyear', array( $this, 'merrychristmas_happynewyear' ) );
add_action( 'wp_ajax_nopriv_merrychristmas_happynewyear', array( $this, 'merrychristmas_happynewyear' ) );

¿Cuál sería la mejor manera de finalizar la función merrychristmas_happynewyear con die(), die(0), wp_die(), u otra alternativa y por qué?

0
Todas las respuestas a la pregunta 8
4
24

Usar wp_die() es la mejor de esas opciones.

Como otros han señalado, hay muchas razones para preferir una función específica de WordPress sobre el simple die o exit:

  • Permite que otros plugins se enganchen a las acciones llamadas por wp_die().
  • Permite usar un manejador especial para la salida basado en el contexto (el comportamiento de wp_die() se adapta dependiendo de si la solicitud es Ajax o no).
  • Hace posible probar tu código.

El último punto es más importante, por eso añadí esa nota al Codex. Si quieres crear pruebas unitarias/integración para tu código, no podrás probar una función que llame directamente a exit o die. Terminará el script, como se supone que debe hacer. La forma en que los tests de WordPress evitan esto (para los callbacks Ajax que tienen pruebas), es engancharse a las acciones activadas por wp_die() y lanzar una excepción. Esto permite capturar la excepción dentro del test y analizar la salida del callback (si la hay).

El único momento en que usarías die o exit es si quieres evitar cualquier manejo especial de wp_die() y terminar la ejecución inmediatamente. Hay algunos lugares donde WordPress hace esto (y otros donde podría usar die directamente solo porque el manejo de wp_die() no es importante, o nadie ha intentado crear pruebas para ese código todavía, así que se pasó por alto). Recuerda que esto también hace tu código más difícil de probar, así que generalmente solo se usaría en código que no está en el cuerpo de una función de todos modos (como hace WordPress en admin-ajax.php). Así que si el manejo de wp_die() no es específicamente deseado, o estás terminando el script en un punto como precaución (como hace admin-ajax.php, esperando que normalmente un callback Ajax ya haya terminado correctamente), entonces podrías considerar usar die directamente.

En cuanto a wp_die() vs wp_die( 0 ), cuál usar depende de qué esté manejando la respuesta de esa solicitud Ajax en el front end. Si espera un cuerpo de respuesta particular, entonces necesitas pasar ese mensaje (o entero, en este caso) a wp_die(). Si solo está esperando que la respuesta sea exitosa (código de respuesta 200 o similar), entonces no hay necesidad de pasar nada a wp_die(). Sin embargo, notaría que terminar con wp_die( 0 ) haría la respuesta indistinguible de la respuesta predeterminada de admin-ajax.php. Así que terminar con 0 no te dice si tu callback se enganchó correctamente y realmente se ejecutó. Un mensaje diferente sería mejor.

Como señalan otras respuestas, a menudo encontrarás que wp_send_json() y similares son útiles si estás enviando una respuesta JSON, lo que generalmente es una buena idea. Esto también es superior a solo llamar a wp_die() con un código, porque puedes devolver mucha más información en un objeto JSON si es necesario. Usar wp_send_json_success() y wp_send_json_error() también enviará el mensaje de éxito/error en un formato estándar que cualquier función de ayuda Ajax de JS proporcionada por WordPress podrá entender (como wp.ajax).

En resumen: Probablemente siempre deberías usar wp_die(), ya sea en un callback Ajax o no. Mejor aún, envía información de vuelta con wp_send_json() y similares.

4 feb 2017 23:51:48
Comentarios

Aportaste algunos buenos puntos de vista. Actualicé el hilo con mis reflexiones. Puedes comentar si lo deseas. @J.D

prosti prosti
7 feb 2017 15:12:25

@prosti Gracias, he añadido un párrafo sobre cuándo y por qué tú/WordPress podríais usar die en lugar de wp_die().

J.D. J.D.
7 feb 2017 16:25:55

Aprecio tu esfuerzo, sin embargo, no entiendo por qué el núcleo de WordPress a veces usaba die() y otras veces wp_die().

prosti prosti
10 feb 2017 11:27:03

Gracias @prosti. En cuanto a por qué WordPress a veces usa die(), en algunos casos es simplemente código heredado, o die() se usa para terminar el script como último recurso cuando algo realmente inesperado sucedió y wp_die() no fue llamado. En otros casos, nadie ha creado pruebas para un fragmento de código, y el manejo especial de wp_die() no es específicamente necesario, por lo que se ha pasado por alto.

J.D. J.D.
10 feb 2017 15:49:45
5
14

Del codex AJAX en Plugins

add_action( 'wp_ajax_my_action', 'my_action_callback' );

function my_action_callback() {
    global $wpdb; // así es como obtienes acceso a la base de datos

    $whatever = intval( $_POST['whatever'] );

    $whatever += 10;

        echo $whatever;

    wp_die(); // esto es necesario para terminar inmediatamente y devolver una respuesta adecuada
}

Observa el uso de wp_die(), en lugar de die() o exit(). La mayoría de las veces deberías usar wp_die() en tu función de callback de Ajax. Esto proporciona una mejor integración con WordPress y facilita las pruebas de tu código.

24 dic 2016 14:23:20
Comentarios

el codex que mencionaste es genial, pero el núcleo de WordPress no lo sigue. ¿Qué opinas de eso?

prosti prosti
25 dic 2016 19:23:14

Todas las funciones wp_send_json_* utilizan wp_send_json que todavía llama a wp_die

Tunji Tunji
25 dic 2016 20:27:25

Pero por qué, me estoy perdiendo algo aquí. ¿Has analizado estas funciones y llegaste a esas conclusiones?

prosti prosti
3 feb 2017 19:02:18

¿te importaría agregar la nota sobre wp_send_json en la respuesta?

Mark Kaplun Mark Kaplun
3 feb 2017 19:18:00

¿cuál es correcto? ¿wp_die(0) o wp_die()?

Anwer AR Anwer AR
4 feb 2017 08:01:36
6
10

También puedes usar wp_send_json() descrito en el Codex como enviar una respuesta JSON de vuelta a una solicitud AJAX y finalizar la ejecución.

Por lo tanto, si necesitas devolver un array, solo tienes que terminar tu función con wp_send_json($array_con_valores);. No es necesario usar echo ni die.

También tienes dos funciones auxiliares wp_send_json_success() y wp_send_json_error() que añaden una clave llamada success que será true o false respectivamente.

Por ejemplo:

$array_val = range( 1,10 );
var_dump( wp_send_json_error( $array_val ) ); # Salida: {"success":false,"data":[1,2,3,4,5,6,7,8,9,10]}
echo 'Hola'; # No se ejecuta porque ya finalizó.
25 dic 2016 15:31:38
Comentarios

wp_json_encode en caso de una excepción puede devolver false, ¿qué pasa en ese caso?

prosti prosti
25 dic 2016 19:21:26

Lanza una excepción si el tercer argumento (profundidad) es menor que 0.

RRikesh RRikesh
26 dic 2016 08:43:44

¿Entonces crees que wp_send_json() es la mejor manera? ¿Por qué?

prosti prosti
3 feb 2017 19:04:16

@prosti wp_send_json() hace algunas cosas por nosotros. Esta pregunta también trata sobre wp_send_json().

RRikesh RRikesh
4 feb 2017 14:49:48

Esto es exactamente @RRikesh por lo que estoy preguntando, el núcleo de WP usa esa función. ¿Entonces por qué esto? ¿Es mejor así?

prosti prosti
4 feb 2017 16:03:13

Menos código manteniendo las cosas concisas. Yo lo encuentro mejor.

RRikesh RRikesh
4 feb 2017 19:28:44
Mostrar los 1 comentarios restantes
0

Para usar AJAX en WordPress / WooCommerce, la sintaxis general es la siguiente:

add_action( 'wp_ajax_my_action', 'my_action_callback' );
add_action( 'wp_ajax_nopriv_my_action', 'my_action_callback' );
function my_action_callback()
{
// tu código va aquí

wp_die();

}

Debes usar wp_die() al final de la función. Porque WordPress internamente usa un filtro durante la función wp_die(). Así que cualquier plugin que funcione usando ese filtro podría no funcionar si no incluimos wp_die(). Además, die() y otras funciones terminan inmediatamente la ejecución de PHP sin considerar las funciones de WordPress que deberían tenerse en cuenta al finalizar la ejecución.

Si estás usando wp_send_json() dentro de tu función como esto:

       function my_action_callback()
    {
    // tu código va aquí

      wp_send_json();

    //wp_die(); no es necesario usar wp_die();

    }

No es necesario usar wp_die() al final si incluyes wp_send_json() dentro de la función de callback. Porque WordPress mismo usa la función wp_die() de forma segura dentro de la función wp_send_json().

6 feb 2017 09:29:51
0

Esto es solo un complemento a lo que otros han dicho. La razón para preferir wp_die es que el núcleo puede activar acciones allí y los plugins pueden completar adecuadamente cosas como rastreo, monitoreo o almacenamiento en caché.

En general, siempre deberías preferir una llamada a la API del núcleo cuando esté disponible, ya que lo más probable es que agregue algún valor (caché, integración con plugins o lo que sea) que no obtendrías con la llamada directa a PHP.

3 feb 2017 19:24:53
0

No aceptaré esta respuesta, no sería justo. Solo quería crear un esquema y posibles pistas sobre los puntos que considero importantes:

La definición principal de wp-die()

Archivo: wp-includes/functions.php
2607: /**
2608:  * Detiene la ejecución de WordPress y muestra un mensaje HTML con el error.
2609:  *
2610:  * Esta función complementa la función `die()` de PHP. La diferencia es que
2611:  * se mostrará HTML al usuario. Se recomienda usar esta función
2612:  * solo cuando la ejecución no deba continuar. No se recomienda
2613:  * llamar a esta función con frecuencia, y se debe intentar manejar tantos errores como sea posible
2614:  * de forma silenciosa o más elegante.
2615:  *
2616:  * Como abreviación, el código de respuesta HTTP deseado puede pasarse como entero
2617:  * al parámetro `$title` (se aplicaría el título por defecto) o al parámetro `$args`.
2618:  *
2619:  * @since 2.0.4
2620:  * @since 4.1.0 Los parámetros `$title` y `$args` se modificaron para aceptar opcionalmente
2621:  *              un entero que se usará como código de respuesta.
2622:  *
2623:  * @param string|WP_Error  $message Opcional. Mensaje de error. Si es un objeto WP_Error,
2624:  *                                  y no es una solicitud Ajax o XML-RPC, se usan los mensajes del error.
2625:  *                                  Por defecto vacío.
2626:  * @param string|int       $title   Opcional. Título del error. Si `$message` es un objeto `WP_Error`,
2627:  *                                  se puede usar el dato de error con la clave 'title' para especificar el título.
2628:  *                                  Si `$title` es un entero, se trata como el código
2629:  *                                  de respuesta. Por defecto vacío.
2630:  * @param string|array|int $args {
2631:  *     Opcional. Argumentos para controlar el comportamiento. Si `$args` es un entero, se trata
2632:  *     como el código de respuesta. Por defecto array vacío.
2633:  *
2634:  *     @type int    $response       El código de respuesta HTTP. Por defecto 200 para solicitudes Ajax, 500 en otros casos.
2635:  *     @type bool   $back_link      Si incluir un enlace para volver. Por defecto false.
2636:  *     @type string $text_direction La dirección del texto. Solo es útil internamente, cuando WordPress
2637:  *                                  aún se está cargando y la configuración regional del sitio no está lista. Acepta 'rtl'.
2638:  *                                  Por defecto el valor de is_rtl().
2639:  * }
2640:  */
2641: function wp_die( $message = '', $title = '', $args = array() ) {
2642: 
2643:   if ( is_int( $args ) ) {
2644:       $args = array( 'response' => $args );
2645:   } elseif ( is_int( $title ) ) {
2646:       $args  = array( 'response' => $title );
2647:       $title = '';
2648:   }
2649: 
2650:   if ( wp_doing_ajax() ) {
2651:       /**
2652:        * Filtra el callback para detener la ejecución de WordPress en solicitudes Ajax.
2653:        *
2654:        * @since 3.4.0
2655:        *
2656:        * @param callable $function Nombre de la función callback.
2657:        */
2658:       $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
2659:   } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
2660:       /**
2661:        * Filtra el callback para detener la ejecución de WordPress en solicitudes XML-RPC.
2662:        *
2663:        * @since 3.4.0
2664:        *
2665:        * @param callable $function Nombre de la función callback.
2666:        */
2667:       $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
2668:   } else {
2669:       /**
2670:        * Filtra el callback para detener la ejecución de WordPress en solicitudes no Ajax ni XML-RPC.
2671:        *
2672:        * @since 3.0.0
2673:        *
2674:        * @param callable $function Nombre de la función callback.
2675:        */
2676:       $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
2677:   }
2678: 
2679:   call_user_func( $function, $message, $title, $args );
2680: }

wp_send_json

Archivo: wp-includes/functions.php
3144: /**
3145:  * Envía una respuesta JSON a una solicitud Ajax.
3146:  *
3147:  * @since 3.5.0
3148:  * @since 4.7.0 Se añadió el parámetro `$status_code`.
3149:  *
3150:  * @param mixed $response    Variable (normalmente un array u objeto) a codificar como JSON,
3151:  *                           luego imprimir y terminar.
3152:  * @param int   $status_code El código de estado HTTP a enviar.
3153:  */
3154: function wp_send_json( $response, $status_code = null ) {
3155:   @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
3156:   if ( null !== $status_code ) {
3157:       status_header( $status_code );
3158:   }
3159:   echo wp_json_encode( $response );
3160: 
3161:   if ( wp_doing_ajax() ) {
3162:       wp_die( '', '', array(
3163:           'response' => null,
3164:       ) );
3165:   } else {
3166:       die;
3167:   }
3168: }

wp_doing_ajax

Archivo: wp-includes/load.php
1044: /**
1045:  * Determina si la solicitud actual es una solicitud Ajax de WordPress.
1046:  *
1047:  * @since 4.7.0
1048:  *
1049:  * @return bool True si es una solicitud Ajax de WordPress, false en caso contrario.
1050:  */
1051: function wp_doing_ajax() {
1052:   /**
1053:    * Filtra si la solicitud actual es una solicitud Ajax de WordPress.
1054:    *
1055:    * @since 4.7.0
1056:    *
1057:    * @param bool $wp_doing_ajax Si la solicitud actual es una solicitud Ajax de WordPress.
1058:    */
1059:   return apply_filters( 'wp_doing_ajax', defined( 'DOING_AJAX' ) && DOING_AJAX );
1060: }

Normalmente lo que obtenemos de una llamada Ajax es algún tipo de respuesta. La respuesta puede estar codificada en json o no.

En caso de necesitar salida json, wp_send_json o dos satélites son una gran idea.

Sin embargo, podemos devolver x-www-form-urlencoded o multipart/form-data o text/xml o cualquier otro tipo de codificación. En ese caso no usamos wp_send_json.

Podemos devolver HTML completo y en ese caso tiene sentido usar wp_die() con el primer y segundo parámetro, de lo contrario estos parámetros deben estar vacíos.

 wp_die( '', '', array(
      'response' => null,
 ) );

¿Pero cuál es el beneficio de llamar a wp_die() sin parámetros?


Finalmente, si revisas el gran núcleo de WP puedes encontrar

Archivo: wp-includes/class-wp-ajax-response.php
139:    /**
140:     * Muestra respuestas formateadas en XML.
141:     *
142:     * Establece la cabecera Content-Type a text/xml.
143:     *
144:     * @since 2.1.0
145:     */
146:    public function send() {
147:        header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ) );
148:        echo "<?xml version='1.0' encoding='" . get_option( 'blog_charset' ) . "' standalone='yes'?><wp_ajax>";
149:        foreach ( (array) $this->responses as $response )
150:            echo $response;
151:        echo '</wp_ajax>';
152:        if ( wp_doing_ajax() )
153:            wp_die();
154:        else
155:            die();

Ambos formatos se usan die() y wp_die(). ¿Puedes explicar por qué?

Finalmente, aquí está lo que devuelve admin-ajax.php: die( '0' );

¿Por qué no wp_die(...)?

7 feb 2017 15:07:25
0

Usa wp_die(). Es mejor utilizar funciones de WordPress tanto como puedas.

5 feb 2017 00:05:53
7

Si usas echo, te obligará a utilizar die(), die(0) o wp_die().

Si no usas echo, JavaScript puede manejar eso.

Entonces deberías usar una mejor manera de devolver datos: wp_send_json().

Para enviar datos en tu callback (en formato json), puedes usar lo siguiente:

wp_send_json()

wp_send_json_success()

wp_send_json_error()

Todos ellos terminarán la ejecución por ti. No es necesario usar exit o die después.

ACTUALIZACIÓN

Y si no necesitas json como formato de salida, deberías usar:

wp_die($response)

Devolverá tu respuesta antes de terminar. Según el codex:

La función wp_die() está diseñada para dar salida justo antes de terminar y así evitar respuestas vacías o que agoten el tiempo de espera.

Lee el artículo completo del codex aquí.

9 feb 2017 16:26:39
Comentarios

Gracias, ¿qué sugieres en lugar de echo?

prosti prosti
9 feb 2017 17:12:59

Para tener en cuenta, Javascript no maneja echo. wp_send_json_* usa echo y finaliza por ti. Hay confusión aquí entre el cliente y el servidor.

Brian Fegter Brian Fegter
9 feb 2017 17:58:13

@prosti wp_send_json()

Faisal Alvi Faisal Alvi
9 feb 2017 18:43:09

Gracias, ¿y en caso de que no necesitemos json como formato de salida?

prosti prosti
9 feb 2017 18:46:59

@prosti entonces deberías usar wp_die($response) porque según el codex: La función wp_die() está diseñada para dar salida justo antes de terminar para evitar respuestas vacías o que agoten el tiempo de espera.

Faisal Alvi Faisal Alvi
9 feb 2017 18:59:39

Gracias, @FaisalAlvi por favor [edita] tu respuesta para hacerla más atractiva para votos positivos. No dejes detalles importantes en los comentarios.

prosti prosti
9 feb 2017 19:24:31

@prosti Gracias. Acabo de actualizar la respuesta.

Faisal Alvi Faisal Alvi
9 feb 2017 19:33:28
Mostrar los 2 comentarios restantes