Если вы когда-либо хотели отправить форму без перезагрузки страницы, предоставьте функцию поиска,заглядывая вперед, которая подсказывает пользователю предложения по мере ввода или автоматического сохранения документов, то вам нужен AJAX (также известный как XHR). Закулисный запрос отправляется на сервер и возвращает данные в форму. Всякий раз, когда вы видите анимацию погрузчика после того, как вы сделали некоторые действия на странице, это, вероятно, запрос AJAX, представленный на сервер.
В этой статье я проведу весь процесс создания и обработки вызовов AJAX. Вы узнаете не только, как сделать звонок AJAX, но и как сделать это наилучшим образом, используя функции, которые WordPress предлагает разработчикам прямо из коробки. Мы создам простой плагин, который позволит читателям отправить отчет администратору с информацией о любой ошибке, которую они могут обнаружить на вашем сайте.
В конце статьи можно загрузить рабочий пример и полностью изучить код.
Давайте копать в!
Ajax
«Без перезагрузки страницы» является ключевым предложением здесь. AJAX означает Asynchronous JavaScript и XML, потому что первоначально данные, возвращенные с сервера, должны быть в XML. Тем не менее, легче отправить их в JSON, который JavaScript любит больше.
Мы собираемся использовать AJAX для отправки электронной почты. Вы не можете сделать это с переднего конца, так что вы должны назвать бэк-энд. Обычно мы отправляем запрос POST на сервер, обрабатываем его и перенаправляем пользователя обратно на страницу с формой. В этой итерации мы не хотим перезагружать страницу. Вместо этого мы вызываем бэкэнд непосредственно там, где мы собираемся захватить данные формы с помощью JavaScript, а затем отправляем асинхронный запрос на сервер для обработки ответа.
Есть три вещи, которые WordPress AJAX необходимо работать — пять из них хорошоработать . К ним относятся:
- Объект для действия AJAX
- JavaScript
- WordPress действий
- Защиты
- Обработка ошибок
Давайте взглянем поближе на каждый из них.
Объекта
Наш объект — форма. Это наша вещь для обработки с JavaScript. Я начал с создания файла с заголовком, необходимых WordPress плагин и положить пустой объект внутри. В конце концов, я создаю новый экземпляр класса плагина.
<?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();
Даже если я использую некоторые OOP здесь, мы не собираемся использовать какие-либо передовые практики. Кодекс будет работать так же хорошо, когда написано процедурно с отдельными функциями. Но объекты в Плагинах WordPress имеют одно преимущество: вы не должны префиксировать свои функции — только название класса должно быть уникальным.
Давайте отобразим нашу форму для пользователей. Мы собираемся подключиться the_content
к фильтру и вставлять форму в конце каждого поста. В конструкторе класса я добавил фильтр:
public function __construct() {
add_filter( 'the_content', array( $this, 'report_button' ), 10, 1 );
}
И создал метод обратного отраки с формой 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_id="' . get_the_ID() . '">' .
__( '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;
}
Форма имеет всю необходимую разметку:
- Кнопка для отображима формы и отправки сообщения;
-
textarea
; - Контейнер для ответа (мы собираемся использовать это позже).
Кнопка имеет data-post_id
атрибут, который хранит текущий идентификатор поста. Мы схватим это в JavaScript для того чтобы определить статью.
Нам нужно только некоторые основные укладка, так что давайте зарегистрировать наш собственный стиль с wp_enqueue_scripts
действием и соответствующего обратного вызова:
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' );
}
Сам стиль очень прост. Мы хотим увести в порядок дизайн.
.report-a-bug-message {
display: none;
margin-top: 1em;
}
.report-a-bug-response {
margin-top: 1em;
}
Вот как выглядит кнопка:
Сценарий
У нас есть наш объект готов положить некоторую жизнь в нем. Вместо того, чтобы делать это в простой JavaScript мы собираемся использовать j’ery который WordPress загружается по умолчанию на каждой странице.
В существующем методе скриптов я добавлю wp_enqueue_script
файл JS с помощью функции.
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' )
) );
}
Я также использую wp_localize_script
функцию, чтобы передать переведенную метку кнопки jS. У нас нет gettext
никаких функций в JavaScript, поэтому мы должны сделать это здесь. Эта функция создаст объект настроек, к которым можно получить доступ непосредственно из нашего скрипта.
В нашем скрипте мы будем слушать нажатие кнопки. Как только это произойдет, мы покажем textarea
и переключить класс кнопки, чтобы прослушать второй клик, который посылает форму.
( 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 );
Вот текущий прогресс:
Это лучшее время для создания запроса AJAX!
AJAX просит WordPress
Чтобы отправить запрос AJAX, вам действительно нужен только один-и-только параметр: запрошенный URL. WordPress имеет специальный файл для AJAX, поэтому мы не должны создавать свои собственные. Это /wp-admin/admin-ajax.php
.
Пока мы находимся в wp-admin
области, этот URL-файл доступен в JS в ajaxurl
переменной. На переднем конце, мы должны пройти эту переменную на наших собственных. К счастью, мы уже использовали wp_localize_script
эту функцию, поэтому мы можем просто добавить еще один ключ к ней:
wp_localize_script( 'report-a-bug', 'settings', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'send_label' => __( 'Send report', 'reportabug' )
) );
Мы подготовили все переменные, поэтому давайте создадим вызов AJAX. Мы собираемся отправить его, как только пользователь нажимает на кнопку во второй раз.
$( '.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' );
} );
} );
Мы слушаем для щелчка на типе мы включили на кнопке раньше.
Как вы можете видеть, я меняю текст кнопки на «…» Почему? Потому что это хорошая практика, чтобы показать пользователю, что что-то происходит. Запросы AJAX зависят от производительности сервера и займут некоторое время. Может быть, 30ms, но, возможно, также 3 секунды. Если после нажатия кнопки, кажется, нет эффекта, скорее всего, кнопка будет нажата во второй раз. Это будет дублировать запрос, потому что, как вы теперь знаете, они асинхронны.
Далее я создаю data
объект. Это содержит все переменные, которые будут отправлены на обратный вызов сервера. admin-ajax.php
WordPress файл требует действий собственности. Это должно быть уникальным, если вы хотите, чтобы другой плагин для обработки ваших запросов. Остальные параметры не являются обязательными. Я посылаю идентификатор сообщения и отчета от textarea
.
Затем мы вызываем $.post
метод. Далее, вы догадались; он отправляет запрос POST. Это метод сокращения, но вы можете использовать $.ajax
метод, а также, который имеет больше вариантов. В качестве первого параметра мы должны пройти наш обработчик файл URL, то параметры, а затем функции обратного вызова успеха. Это место, где мы обрабатываем ответ. На данный момент мы просто отправляем простое сообщение на консоль браузера.
Мы готовы вынести запрос на бэк-энде.
WordPress действий
Вы можете быть удивлены, как мы подключить в admin-ajax.php. С действием, конечно! WordPress имеет два типа действий:
wp_ajax_nopriv_{$action}
wp_ajax_{$action}
Где $action
находится, имя действия прошло в AJAX params. Это send_bug_report
в нашем случае.
Первое из этих действий будет выполнено только для пользователей, не зарегистрированных в журнале. Второй только для зарегистрированных пользователей. Так что если вы хотите, чтобы запрос был обработан для обоих, вы должны определить и то, и другое. Это то, что я сделал в классе ‘конструктор:
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' ) );
}
В обратный вызов, я просто получаю название поста, и я посылаю по электронной почте:
function send_bug_report() {
$data = $_POST;
$post_title = get_the_title( intval( $data['post_id'] ) );
wp_mail( 'admin@ema.il', 'Bug report in post: ' . $post_title, $data['report'] );
wp_send_json_success( __( 'Thanks for reporting!', 'reportabug' ) );
}
Наиболее важной частью с точки зрения обработки AJAX в WordPress является последняя функция — wp_send_json_success
которая печатает JSON закодированный выход и умирает. Все, что нам нужно, чтобы захватить ответ с успехом AJAX обратный вызов. Он также брат-близнец, wp_send_json_error
, но мы получим в этой части позже.
Объект из этих функций имеет два свойства:
-
Успех
Является boolean и зависит, если вы называете это успех или ошибка функции. -
Данных
Если вы предоставляете параметр для функции.
Это все с задней стороны. Давайте разожм ответ в JS.
Мы удалим кнопку и textarea и отображаем сообщение, возвращенное с сервера в контейнере, который мы подготовили ранее:
$.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 );
});
И это все! У нас есть рабочий вызов AJAX! Но не останавливайтесь на достигнутом. Наша просьба не является безопасной и, конечно, не удобной для пользователя. Мы должны убедиться, что запрос выполняется только тогда, когда это необходимо.
Защиты
Nonce
Nonce — это «число, используемое один раз». Это короткий хэш, созданный из строки ввода. Мы можем использовать его для проверки запроса — если он действительно был сделан WordPress, и никто не подделывает его.
Мы собираемся использовать другой атрибут данных для кнопки:
$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_id="' . get_the_ID() . '">' .
__( '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>';
Как вы можете видеть, я добавляю идентификатор публикации в строку ввода. Этот идентификатор будет доступен в свойствах запроса AJAX, так что он просто более безопасным.
Теперь мы должны добавить nonce к свойствам 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()
};
Теперь мы будем проверять его check_ajax_referer
в бэкэнде с помощью функции, которая 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( 'admin@ema.il', 'Bug report in post: ' . $post_title, sanitize_text_field( $data['report'] ) );
wp_send_json_success( __( 'Thanks for reporting!', 'reportabug' ) );
}
Для проверки запроса мы должны регенерировать строку ввода, поэтому я использую post_id
ключ, отправленный из AJAX. Второй параметр является ключевым в $_REQUEST array
. Третий контролирует wp_die
автоматизированную, если nonce не соответствует.
Я не хочу, чтобы он умер сам. Вместо этого я ловлю результат этой функции и отправляю ошибку JSON в хороший объект.
Вы также можете заметить sanitize_text_field
использование функции в параметре сообщения электронной почты. Это просто, чтобы убедиться, что пользователь не будет отправлять вредные скрипты или HTML.
Наконец, нам нужно обернуть обратный вызов успеха AJAX в JS, если заявление, чтобы проверить, если запрос был успешным:
$.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 );
}
});
Защита от нокнов
Вы знаете, что пользователь может нажать на кнопку во второй раз, прежде чем AJAX закончит вызов. Но есть один простой трюк, который будет блокировать второй клик — отключение кнопки. Поэтому после клика, я собираюсь заблокировать его и разблокировать его после получения ответа:
$('.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);
});
});
Обработка ошибок
Проверки
Что делать, если пользователь пытается отправить пустое сообщение? Я не хочу, чтобы меня беспокоили такие письма. Давайте блокировать эти попытки с помощью методов проверки.
В JS я собираюсь добавить простую проверку, чтобы показать пользователю, что что-то пошло не так. Если сообщение пусто, пользователь увидит красную границу вокруг области текста. Если сообщение присутствует там, мы восстанавливаем нейтральную границу:
$('.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
});
Проверка на наличие ошибок в действии WordPress
У нас также могут возникнуть проблемы с отправкой электронной почты. Если мы не проверим результат wp_mail
функции, пользователь получит сообщение об успехе, даже если письмо не было отправлено.
Давайте разберусь с этим:
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( 'admin@ema.il', '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();
}
}
Как вы видите, мы использовали wp_send_json_error
эту функцию дважды, но нет необходимости отображать уникальные сообщения для пользователей. Вместо этого, передавая точное описание ошибки, я собираюсь добавить еще один ключ к нашему объекту настроек скрипта, который будет охватывать обе ошибки:
// 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' )
) );
Все, что осталось сделать, это отобразить ошибку для пользователя:
$.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 );
} );
Полный пример
Мы сделали это! Наш запрос AJAX был сделан; это хорошо защищены и удобный. Это то, что пользователь будет видеть в случае каких-либо ошибок:
Ниже вы можете скачать полный плагин и проверить руководство пользователя:
Я надеюсь, что это дает вам хороший фундамент для ваших собственных «без страницы обновления» решения. Вы можете сделать это для всех форм на вашем сайте. Это также отличный способ оптимизировать любой тяжелый кусок веб-сайта, который не должен быть загружен сразу, например, большой список продуктов в падение вниз. Вы можете загрузить их через AJAX сразу после нажатия на падение вниз — это так просто.
Возможности практически безграничны. Препятствуйте мне знать в комментариях чего ваши идеи!
Источник: smashingmagazine.com