Лучший способ завершения WordPress ajax запроса и почему?

24 дек. 2016 г., 14:18:20
Просмотры: 21.7K
Голосов: 24

Рассматривая стандартные WordPress ajax запросы, такие как:

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

Как лучше всего завершить функцию merrychristmas_happynewyear - используя die(), die(0), wp_die(), или что-то другое, и почему?

0
Все ответы на вопрос 8
4
24

Использование wp_die() является лучшим из предложенных вариантов.

Как уже отмечали другие, есть много причин предпочесть специфичную для WordPress функцию обычным die или exit:

  • Она позволяет другим плагинам подключаться к действиям, вызываемым wp_die().
  • Она позволяет использовать специальный обработчик завершения в зависимости от контекста (поведение wp_die() адаптируется в зависимости от того, является ли запрос Ajax-запросом или нет).
  • Это делает возможным тестирование вашего кода.

Последний пункт особенно важен, поэтому я добавил эту заметку в Codex. Если вы хотите создавать модульные/интеграционные тесты для своего кода, вы не сможете протестировать функцию, которая вызывает exit или die напрямую. Она завершит выполнение скрипта, как и должна. Способ, которым WordPress обходит это в своих тестах (для Ajax-обработчиков, которые тестируются), заключается в подключении к действиям, запускаемым wp_die(), и генерации исключения. Это позволяет перехватить исключение в тесте и проанализировать вывод обработчика (если он есть).

Единственный случай, когда стоит использовать die или exit, — это если вы хотите обойти специальную обработку wp_die() и немедленно завершить выполнение. В WordPress есть несколько мест, где это делается (а также места, где может использоваться die напрямую просто потому, что обработка через wp_die() не важна или никто не пытался создать тесты для этого кода, поэтому это упустили). Помните, что это также усложняет тестирование вашего кода, поэтому обычно такое используется только в коде, который не находится в теле функции (как это делает WordPress в admin-ajax.php). Таким образом, если обработка через wp_die() явно нежелательна или вы завершаете скрипт в определённом месте в качестве меры предосторожности (как делает admin-ajax.php, предполагая, что Ajax-обработчик уже корректно завершил выполнение), то можно рассмотреть использование die напрямую.

Что касается выбора между wp_die() и wp_die( 0 ), то это зависит от того, как обрабатывается ответ на этот Ajax-запрос на фронтенде. Если ожидается определённое тело ответа, то вам нужно передать это сообщение (или число, в данном случае) в wp_die(). Если важно только успешное завершение запроса (код ответа 200 или другой), то передавать что-либо в wp_die() не нужно. Однако стоит отметить, что завершение с wp_die( 0 ) сделает ответ неотличимым от стандартного ответа admin-ajax.php. Таким образом, завершение с 0 не покажет, был ли ваш обработчик правильно подключён и действительно выполнился. Лучше использовать другое сообщение.

Как уже отмечалось в других ответах, часто полезными оказываются функции wp_send_json() и подобные, если вы отправляете JSON-ответ, что обычно является хорошей практикой. Это также лучше, чем просто вызывать wp_die() с кодом, потому что вы можете передать гораздо больше информации в JSON-объекте, если это необходимо. Использование wp_send_json_success() и wp_send_json_error() также отправляет сообщение об успехе/ошибке в стандартном формате, который смогут понять JS-вспомогательные функции WordPress для Ajax (например, wp.ajax).

Коротко: Вероятно, вам всегда следует использовать wp_die(), независимо от того, является ли это Ajax-обработчиком или нет. Ещё лучше — отправлять информацию с помощью wp_send_json() и подобных функций.

4 февр. 2017 г. 23:51:48
Комментарии

Вы добавили несколько хороших точек зрения. Я обновил тему своими мыслями. Можете оставить комментарий, если хотите. @J.D

prosti prosti
7 февр. 2017 г. 15:12:25

@prosti Спасибо, я добавил абзац о том, когда и почему вы/WordPress можете использовать die вместо wp_die().

J.D. J.D.
7 февр. 2017 г. 16:25:55

Ценю ваши усилия, однако, я не понимаю, почему в ядре WordPress иногда используется die(), а иногда wp_die().

prosti prosti
10 февр. 2017 г. 11:27:03

Спасибо @prosti. Что касается того, почему WordPress иногда использует die(), в некоторых случаях это просто устаревший код, или die() используется для аварийного завершения скрипта в крайнем случае, когда произошло что-то действительно непредвиденное и wp_die() не был вызван. В других случаях для части кода просто не были созданы тесты, и специальная обработка из wp_die() не требуется, поэтому это было упущено.

J.D. J.D.
10 февр. 2017 г. 15:49:45
5
14

Из кодекса AJAX в плагинах

add_action( 'wp_ajax_my_action', 'my_action_callback' );

function my_action_callback() {
    global $wpdb; // получаем доступ к базе данных

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

    $whatever += 10;

        echo $whatever;

    wp_die(); // обязательно для немедленного завершения и возврата корректного ответа
}

Обратите внимание на использование wp_die() вместо die() или exit(). В большинстве случаев в функции обратного вызова Ajax следует использовать именно wp_die(). Это обеспечивает лучшую интеграцию с WordPress и упрощает тестирование кода.

24 дек. 2016 г. 14:23:20
Комментарии

Упомянутый вами ccodex отличный, но WordPress core его не придерживается. Как насчет этого?

prosti prosti
25 дек. 2016 г. 19:23:14

Все функции wp_send_json_* используют wp_send_json, который по-прежнему вызывает wp_die

Tunji Tunji
25 дек. 2016 г. 20:27:25

Но почему, я что-то упускаю. Вы проанализировали эти функции и пришли к таким выводам?

prosti prosti
3 февр. 2017 г. 19:02:18

не возражаешь добавить примечание о wp_send_json в ответ?

Mark Kaplun Mark Kaplun
3 февр. 2017 г. 19:18:00

что правильно? wp_die(0) или wp_die()?

Anwer AR Anwer AR
4 февр. 2017 г. 08:01:36
6
10

Вы также можете использовать wp_send_json(), описанную в Codex как отправить JSON-ответ на AJAX-запрос и завершить выполнение (die()).

Таким образом, если вам нужно вернуть массив, просто завершите свою функцию вызовом wp_send_json($array_with_values);. Нет необходимости использовать echo или die.

Также доступны две вспомогательные функции: wp_send_json_success() и wp_send_json_error(), которые добавляют ключ success со значением true или false соответственно.

Например:

$array_val = range( 1,10 );
var_dump( wp_send_json_error( $array_val ) ); # Вывод: {"success":false,"data":[1,2,3,4,5,6,7,8,9,10]}
echo 'Привет'; # Не выполнится, так как выполнение уже завершено.
25 дек. 2016 г. 15:31:38
Комментарии

Функция wp_json_encode в случае исключения может вернуть false. Что делать в таком случае?

prosti prosti
25 дек. 2016 г. 19:21:26

Она выбрасывает исключение, если третий аргумент (depth) меньше 0.

RRikesh RRikesh
26 дек. 2016 г. 08:43:44

Ты считаешь, что wp_send_json() — это лучший способ? Почему?

prosti prosti
3 февр. 2017 г. 19:04:16

@prosti wp_send_json() делает некоторые вещи за нас. Этот вопрос также касается wp_send_json().

RRikesh RRikesh
4 февр. 2017 г. 14:49:48

Именно поэтому @RRikesh я спрашиваю, использует ли WP core эту функцию. Так зачем это? Так лучше?

prosti prosti
4 февр. 2017 г. 16:03:13

Меньше кода, сохраняя лаконичность. Я считаю, что так лучше.

RRikesh RRikesh
4 февр. 2017 г. 19:28:44
Показать остальные 1 комментариев
0

Для использования AJAX в WordPress / WooCommerce общий синтаксис следующий:

add_action( 'wp_ajax_my_action', 'my_action_callback' );
add_action( 'wp_ajax_nopriv_my_action', 'my_action_callback' );
function my_action_callback()
{
// ваш код здесь

wp_die();

}

В конце функции следует использовать wp_die(). Потому что WordPress внутренне использует фильтр во время выполнения функции wp_die(). Поэтому любой плагин, который работает с этим фильтром, может не работать, если мы не включим wp_die(). Также функции die() и другие немедленно завершают выполнение PHP без учета каких-либо функций WordPress, которые должны быть учтены при завершении выполнения.

Если вы используете wp_send_json() внутри функции, как здесь:

       function my_action_callback()
    {
    // ваш код здесь

      wp_send_json();

    //wp_die(); не обязательно использовать wp_die();

    }

Необязательно использовать wp_die() в конце, если вы включаете wp_send_json() внутри callback-функции, потому что WordPress сам безопасно использует функцию wp_die() внутри функции wp_send_json().

6 февр. 2017 г. 09:29:51
0

Это дополнение к тому, что уже сказали другие. Причина, по которой стоит предпочесть wp_die, заключается в том, что ядро WordPress может запускать действия в этом месте, а плагины могут корректно завершать такие вещи, как трассировка, мониторинг или кеширование.

В целом, если доступен вызов API ядра, всегда стоит предпочесть его, так как он, скорее всего, добавляет какую-то ценность (кеширование, интеграция с плагинами или что-то ещё), чего вы не получите при прямом вызове PHP-функции.

3 февр. 2017 г. 19:24:53
0

Я не приму этот ответ, это было бы несправедливо. Я просто хотел создать структуру и возможные подсказки по пунктам, которые считаю важными:

Основное определение wp-die()

Файл: wp-includes/functions.php
2607: /**
2608:  * Прерывает выполнение WordPress и отображает HTML-сообщение с ошибкой.
2609:  *
2610:  * Эта функция дополняет PHP-функцию `die()`. Разница в том, что
2611:  * пользователю будет отображён HTML. Рекомендуется использовать эту функцию
2612:  * только когда выполнение не должно продолжаться дальше. Не рекомендуется
2613:  * вызывать эту функцию часто, по возможности обрабатывайте ошибки
2614:  * "тихо" или более изящно.
2615:  *
2616:  * В качестве сокращения, желаемый HTTP-код ответа может быть передан как целое число
2617:  * в параметр `$title` (будет применён заголовок по умолчанию) или в параметр `$args`.
2618:  *
2619:  * @since 2.0.4
2620:  * @since 4.1.0 Параметры `$title` и `$args` были изменены для опционального приёма
2621:  *              целого числа в качестве кода ответа.
2622:  *
2623:  * @param string|WP_Error  $message Опционально. Сообщение об ошибке. Если это объект WP_Error,
2624:  *                                  и запрос не Ajax или XML-RPC, используются сообщения ошибки.
2625:  *                                  По умолчанию пусто.
2626:  * @param string|int       $title   Опционально. Заголовок ошибки. Если `$message` это `WP_Error`,
2627:  *                                  данные ошибки с ключом 'title' могут использоваться для указания заголовка.
2628:  *                                  Если `$title` это число, оно трактуется как код
2629:  *                                  ответа. По умолчанию пусто.
2630:  * @param string|array|int $args {
2631:  *     Опционально. Аргументы для управления поведением. Если `$args` это число, оно трактуется
2632:  *     как код ответа. По умолчанию пустой массив.
2633:  *
2634:  *     @type int    $response       HTTP-код ответа. По умолчанию 200 для Ajax-запросов, иначе 500.
2635:  *     @type bool   $back_link      Включать ли ссылку "назад". По умолчанию false.
2636:  *     @type string $text_direction Направление текста. Полезно только внутренне, когда WordPress
2637:  *                                  ещё загружается и локаль сайта не установлена. Принимает 'rtl'.
2638:  *                                  По умолчанию значение 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:        * Фильтрует callback для прерывания выполнения WordPress для Ajax-запросов.
2653:        *
2654:        * @since 3.4.0
2655:        *
2656:        * @param callable $function Имя callback-функции.
2657:        */
2658:       $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
2659:   } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
2660:       /**
2661:        * Фильтрует callback для прерывания выполнения WordPress для XML-RPC запросов.
2662:        *
2663:        * @since 3.4.0
2664:        *
2665:        * @param callable $function Имя callback-функции.
2666:        */
2667:       $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
2668:   } else {
2669:       /**
2670:        * Фильтрует callback для прерывания выполнения WordPress для всех не-Ajax, не-XML-RPC запросов.
2671:        *
2672:        * @since 3.0.0
2673:        *
2674:        * @param callable $function Имя 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

Файл: wp-includes/functions.php
3144: /**
3145:  * Отправляет JSON-ответ на Ajax-запрос.
3146:  *
3147:  * @since 3.5.0
3148:  * @since 4.7.0 Добавлен параметр `$status_code`.
3149:  *
3150:  * @param mixed $response    Переменная (обычно массив или объект) для кодирования в JSON,
3151:  *                           затем вывод и завершение.
3152:  * @param int   $status_code HTTP-код статуса для вывода.
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

Файл: wp-includes/load.php
1044: /**
1045:  * Определяет, является ли текущий запрос WordPress Ajax-запросом.
1046:  *
1047:  * @since 4.7.0
1048:  *
1049:  * @return bool True, если это WordPress Ajax-запрос, иначе false.
1050:  */
1051: function wp_doing_ajax() {
1052:   /**
1053:    * Фильтрует, является ли текущий запрос WordPress Ajax-запросом.
1054:    *
1055:    * @since 4.7.0
1056:    *
1057:    * @param bool $wp_doing_ajax Является ли текущий запрос WordPress Ajax-запросом.
1058:    */
1059:   return apply_filters( 'wp_doing_ajax', defined( 'DOING_AJAX' ) && DOING_AJAX );
1060: }

Обычно мы получаем от ajax-запроса какой-то ответ. Ответ может быть закодирован в json или может быть не закодирован в json.

Если нам нужен вывод в формате json, то wp_send_json или два сателлита — отличная идея.

Однако мы можем вернуть x-www-form-urlencoded, multipart/form-data, text/xml или любой другой тип кодировки. В этом случае мы не используем wp_send_json.

Мы можем вернуть целый HTML, и в этом случае имеет смысл использовать wp_die() с первым и вторым параметром, иначе эти параметры должны быть пустыми.

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

Но в чём преимущество вызова wp_die() без параметров?


Наконец, если вы проверите отличное ядро WP, вы можете найти

Файл: wp-includes/class-wp-ajax-response.php
139:    /**
140:     * Отображает ответы в формате XML.
141:     *
142:     * Устанавливает заголовок Content-Type в 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();

Используются оба формата: die() и wp_die(). Можете объяснить почему?

Наконец, вот что возвращает admin-ajax.php: die( '0' );

Почему не wp_die(...)?

7 февр. 2017 г. 15:07:25
0

Используйте wp_die(). По возможности лучше использовать функции WordPress.

5 февр. 2017 г. 00:05:53
7

Если вы используете echo, это заставит вас использовать die(), die(0) или wp_die().

Если вы не используете echo, JavaScript может обработать это.

Тогда вам следует использовать более правильный способ возврата данных: wp_send_json().

Чтобы отправить данные в вашем колбэке (в формате json), вы можете использовать следующие функции:

wp_send_json()

wp_send_json_success()

wp_send_json_error()

Все они завершат выполнение за вас. Не нужно вызывать exit или die после них.

ОБНОВЛЕНИЕ

И если вам не нужен json в качестве формата вывода, используйте:

wp_die($response)

Он вернёт ваш ответ перед завершением работы. Как указано в кодексе:

Функция wp_die() предназначена для вывода данных перед завершением, чтобы избежать пустых или зависающих ответов.

Прочтите полную статью в кодексе здесь.

9 февр. 2017 г. 16:26:39
Комментарии

Спасибо, что вы предложите вместо echo?

prosti prosti
9 февр. 2017 г. 17:12:59

Стоит отметить, что Javascript не работает с echo. wp_send_json_* использует echo и завершает выполнение за вас. Здесь есть путаница между клиентом и сервером.

Brian Fegter Brian Fegter
9 февр. 2017 г. 17:58:13

@prosti wp_send_json()

Faisal Alvi Faisal Alvi
9 февр. 2017 г. 18:43:09

Спасибо, а что если нам не нужен формат вывода json?

prosti prosti
9 февр. 2017 г. 18:46:59

@prosti тогда вам следует использовать wp_die($response), потому что, согласно кодексу: функция wp_die() предназначена для вывода данных непосредственно перед завершением работы, чтобы избежать пустых ответов или таймаутов.

Faisal Alvi Faisal Alvi
9 февр. 2017 г. 18:59:39

Спасибо, @FaisalAlvi, пожалуйста, [отредактируйте] ваш ответ, чтобы он выглядел привлекательно для голосов. Не оставляйте важные детали в комментариях.

prosti prosti
9 февр. 2017 г. 19:24:31

@prosti Спасибо. Только что обновил ответ.

Faisal Alvi Faisal Alvi
9 февр. 2017 г. 19:33:28
Показать остальные 2 комментариев