eurobyte.ru - мощные сервера с Дата-центрами в Нидерландах и Москве. От 159 ₽/мес.

Ajax в WordPress

Цель этой статьи показать, как использовать AJAX при создании тем и плагинов.

Полезное по теме:

Видео уроки об AJAX в WordPress:

AJAX в админ-панели WordPress

С тех пор, как AJAX был встроен в админ-панель WP, использовать функционал AJAX в плагинах стало очень удобно. Небольшой пример. Все делается в одном файле (файле плагина или файле темы functions.php).

#1. Добавляем javascript

Сначала добавляем на страницу админки javascript код, который будет посылать AJAX запрос.

<?php
//add_action( 'admin_print_scripts', 'my_action_javascript' ); // такое подключение будет работать не всегда
add_action( 'admin_print_footer_scripts', 'my_action_javascript', 99 );
function my_action_javascript() {
	?>
	<script>
	jQuery(document).ready( function( $ ){
		var data = {
			action: 'my_action',
			whatever: 1234
		};

		// с версии 2.8 'ajaxurl' всегда определен в админке
		jQuery.post( ajaxurl, data, function( response ){
			alert( 'Получено с сервера: ' + response );
		} );
	} );
	</script>
	<?php
}
?>

С версии 2.8 javascript переменная ajaxurl определена глобально на всех страницах админки. Используйте её в js коде, как ссылку на файл обработчик AJAX запроса. Обычно это файл /wp-admin/admin-ajax.php. В теме (шаблоне) эта переменная не определена. Чтобы использовать её во фронт-энде, её нужно определить самостоятельно. Как это сделать смотрите ниже.

#2. Создаем PHP функцию

Теперь, создадим PHP функцию, которая будет обрабатывать переданный AJAX запрос. Для этого добавляем следующий код в functions.php (можно в плагин):

add_action( 'wp_ajax_my_action', 'my_action_callback' );
function my_action_callback(){
	$whatever = intval( $_POST['whatever'] );

	$whatever += 10;
	echo $whatever;

	// выход нужен для того, чтобы в ответе не было ничего лишнего,
	// только то что возвращает функция
	wp_die();
}

Тут мы цепляемся на хук wp_ajax_my_action - это динамический хук и выглядит он так: wp_ajax_(action), где вместо (action) вставляется значение переменной передаваемой в первом коде: action = my_action.

Вот и все.

Примера выше достаточно, чтобы начать использовать AJAX в админ-панели WordPress.

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

AJAX на фронтэнде (в теме)

Во фронт-энде нужно использовать еще один хук для обработки AJAX запросов: wp_ajax_nopriv_(action).

Этот хук в отличии от wp_ajax_(action), срабатывает для неавторизованных пользователей.

wp_ajax_nopriv_(action) можно не указывать, если не нужно, чтобы AJAX запрос обрабатывался для неавторизованных пользователей.

Таким образов, чтобы создать обработчик запроса для всех пользователей (авторизованных и нет), PHP функцию нужно прикреплять сразу к двум хукам:

add_action( 'wp_ajax_(action)', 'my_action_callback' );
add_action( 'wp_ajax_nopriv_(action)', 'my_action_callback' );

function my_action_callback(){
	// обрабатываем AJAX
}

Переменная ajaxurl

По умолчанию на фронте не создается переменная window.ajaxurl (как в админке), поэтому, чтобы делать запросы на файл admin-ajax.php нам нужно создать переменную которая будет содержать УРЛ и которую мы затем будем использовать для Аякс запросов.

Давайте назовем её по-другому - window.myajax.url. Для фронта так удобнее, потому что в объект window.myajax в будущем можно будет добавить какие-то дополнительные глобальные данные связанные с AJAX.

Вариант 1:

Чтобы не возиться с идентификаторами скриптов, можно просто добавить нужные данные в начало HEAD документа перед подключением скриптов, так:

// NOTE: 8 - before `wp_print_head_scripts`
add_action( 'wp_head', 'myajax_data', 8 );
function myajax_data(){
	$data = [
		'url' => admin_url( 'admin-ajax.php' ),
	];
	?>
	<script id="myajax_data">
		window.myajax = <?= wp_json_encode( $data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ) ?>
	</script>
	<?php
}

Вариант 2:

В этом варианте мы добавим наши Аякс данные, перед подключением указанного скрипта. Для этого будем использовать функцию wp_add_inline_script().

Плюс этого подхода в том, что наши Аякс данные не будут добавлены вообще, если указанный скрипт не будет подключен на странице, т.е. они связаны непосредственно с подключаемым js файлом.

// Подключаем AJAX данные.
// Приоритет 9999 нужен чтобы быть уверенным что 'theme-scripts' уже добавлен в очередь на вывод.
// Заметка: код можно вставить в любое место functions.php темы
add_action( 'wp_enqueue_scripts', 'myajax_data', 9999 );
function myajax_data(){
	$data = [
		'url' => admin_url( 'admin-ajax.php' )
	];

	wp_add_inline_script(
		'theme-scripts',
		'window.myajax = ' . wp_json_encode( $data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ),
		'before'
	);
}

В результате, получим в head части сайта прямо перед скриптом 'my-script-id':

<script type="text/javascript" id="theme-scripts-js-before">
/* <![CDATA[ */
window.myajax = {"url":"https://example.com/wp-admin/admin-ajax.php"}
/* ]]> */
</script>
<script type="text/javascript" src="https://example.com/wp-content/themes/elena/assets/js/scripts.min.js" id="theme-scripts-js"></script>

Запрос через jQuery.ajax()

Первое в чем нужно убедиться - установлена ли на сайте библиотека jQuery.

Пример AJAX кода для фронт энда

<?php
add_action( 'wp_footer', 'my_action_javascript', 99 ); // для фронта
function my_action_javascript() {
	?>
	<script>
	jQuery(document).ready(function($) {
		var data = {
			action: 'my_action',
			whatever: 1234
		};

		// 'ajaxurl' не определена во фронте, поэтому мы добавили её аналог с помощью wp_localize_script()
		jQuery.post( myajax.url, data, function(response) {
			alert('Получено с сервера: ' + response);
		});
	});
	</script>
	<?php
}

add_action( 'wp_ajax_my_action', 'my_action_callback' );
add_action( 'wp_ajax_nopriv_my_action', 'my_action_callback' );
function my_action_callback() {
	$whatever = intval( $_POST['whatever'] );

	echo $whatever + 10;

	// выход нужен для того, чтобы в ответе не было ничего лишнего, только то что возвращает функция
	wp_die();
}

Код рассчитан на тему twentyfifteen. Вставлять код можно в functions.php темы.

Этот код будет работать для любой темы, единственное что для этого нужно - это поменять название основного скрипта темы twentyfifteen-script, который подключается после jquery.

Запрос через fetch()

Если на проекте не используется jQuery. То запрос можно сделать с помощью fetch().

Проблема c fetch() в том, что admin-ajax.php получает $action только из PHP переменных $_POST или $_GET, а fetch() по умолчанию отправляет body данные в php://input поток.

Поэтому если указать "action" в "body" (что обычно делается при POST запросах), то WP не найдет $action и не запускает нужный хук, на который мы вешает коллбэк обработчик аякс запроса.

Чтобы решить эту проблему POST запрос в fetch() нужно отправлять "правильно". Тут возможны два варианта:

Вариант 1:

Указать в "body" объект URLSearchParams() и передать заголовок application/x-www-form-urlencoded.

Благодаря этому в итоге данные попадут в супер-глобальную переменную PHP $_POST.

const requestData = {
	action : 'add_aplication',
	info : 'some info'
}

const queryData = new URLSearchParams();
for ( const key in requestData ) {
	queryData.set( key, requestData[ key ] )
}

fetch( ajaxurl.url, {
	method: "POST",
	body: queryData,
	headers: {
		'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
	},
} )
	 .then( response => response.text() )
	 .then( response => {
		console.log( response );
	 } );

Вариант 2:

Указать в "body" объект FormData().

const form = document.querySelector( 'form.my-form' );

let formData = new FormData( form )
formData.set( 'action', 'add_aplication' )

fetch( ajaxurl.url, {
	method: "POST",
	body: formData,
} )
	 .then( response => response.text())
	 .then( response => {
		console.log(response);
	 } );

Логичное подключение AJAX хуков

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

Коллбэк функции установленные хукам:

Оба хука всегда удовлетворяют условию wp_doing_ajax():

if( wp_doing_ajax() ){}

// до версии WP 4.7
if( defined('DOING_AJAX') ){}

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

Используя это правило, можно не подключать хуки там где в этом нет смысла. Например, при генерации страницы шаблона или страницы админки. Эта маленькая деталь добавит больше логики в код и в некоторых случаях может избавить от багов.

Пример того, как рекомендуется подключать все AJAX хуки.

// подключаем AJAX обработчики, только когда в этом есть смысл
if( wp_doing_ajax() ){
	add_action( 'wp_ajax_myaction', 'ajax_handler' );
	add_action( 'wp_ajax_nopriv_myaction', 'ajax_handler' );
}

// или так до WP 4.7
if( defined('DOING_AJAX') ){
	add_action( 'wp_ajax_myaction', 'ajax_handler' );
	add_action( 'wp_ajax_nopriv_myaction', 'ajax_handler' );
}

В этом случае хуки будут подключены только во время AJAX запроса и не будут подключены при простом посещении фронта, админки, REST или CRON запросе.

Напомню также, что данные отправляемые с фронтэнда на файл wp-admin/admin-ajax.php обработаются указанной в хуке функцией ajax_handler(), независимо авторизован пользователь или нет.

Защита: используем nonce и проверяем права

Нет острой необходимости проверять AJAX запрос, если он потенциально не опасный. Например, когда он просто получает какие-то данные. Но когда запрос удаляет или обновляет данные, то его просто необходимо дополнительно защитить с помощью nonce кода и проверкой прав доступа.

Разработчики часто ленятся ставить такую защиту, получая самый неожиданный результат. Недобросовестные пользователи могут каким-либо образом заставить юзера с правами сделать то что им нужно и в итоге навредить сайту над которым вы работали долгие месяцы, годы.

Существует два вида защиты, которые нужно использовать в AJAX запросах в большинстве случаев.

1. Код nonce (случайный код)

Nonce - это уникальная строка, которая создается и используется один раз - одноразовое число. Nonce проверка используется, когда нужно убедится, что запрос был послан с указанного «места».

В WordPress есть функции wp_create_nonce() и check_ajax_referer() - это базовые функции для создания и последующей проверки nonce кода. С их помощью мы и будем создавать защиту nonce для AJAX запросов.

Для начала создадим nonce код:

add_action( 'wp_enqueue_scripts', 'myajax_data', 99 );
function myajax_data(){

	wp_localize_script( 'twentyfifteen-script', 'myajax',
		array(
			'url' => admin_url('admin-ajax.php'),
			'nonce' => wp_create_nonce('myajax-nonce')
		)
	);

}

twentyfifteen-script это название основного скрипта темы (см. выше), который подключается на сайте с помощью wp_enqueue_script().

Затем, в AJAX запросе добавим переменную с кодом nonce:

var ajaxdata = {
	action     : 'myajax-submit',
	nonce_code : myajax.nonce
};
jQuery.post( myajax.url, ajaxdata, function( response ) {
	alert( response );
});

Теперь, в обработке заброса необходимо проверить nonce код:

add_action( 'wp_ajax_nopriv_myajax-submit', 'myajax_submit' );
add_action( 'wp_ajax_myajax-submit', 'myajax_submit' );
function myajax_submit(){
	// проверяем nonce код, если проверка не пройдена прерываем обработку
	check_ajax_referer( 'myajax-nonce', 'nonce_code' );
	// или так
	if( ! wp_verify_nonce( $_POST['nonce_code'], 'myajax-nonce' ) ) die( 'Stop!');

	// обрабатываем данные и возвращаем
	echo 'Возвращаемые данные';

	// не забываем завершать PHP
	wp_die();
}

check_ajax_referer() работает на основе функции wp_verify_nonce() и по сути является её оберткой для AJAX запросов.

Обратите внимание, что в данном случае Nonce код создается в HTML коде. А это значит, что если у вас установлен плагин страничного кэширования, то этот код может, и наверняка будет устаревать к моменту очередного AJAX запроса, потому что HTML код кэшируется...

2. Проверка прав доступа

Тут AJAX запросы будут срабатывать только для пользователей с правом указанным правом, например author. Для всех остальных, включая неавторизованных пользователей, AJAX запрос вернет ошибку.

Особенность тут в том, что не авторизованные пользователи тоже должны видеть сообщение об ошибке при AJAX запросе. Поэтому для них тоже нужно обрабатывать запрос и вернуть сообщение об ошибке:

add_action( 'wp_ajax_nopriv_myajax-submit', 'myajax_submit' );
add_action( 'wp_ajax_myajax-submit', 'myajax_submit' );
function myajax_submit(){
	// проверяем nonce код, если проверка не пройдена прерываем обработку
	check_ajax_referer( 'myajax-nonce', 'nonce_code' );

	// текущий пользователь не имеет права автора или выше
	if( ! current_user_can('publish_posts') )
		die('Этот запрос доступен пользователям с правом автора или выше.')

	// ОК. У юзера есть нужные права!

	// Делаем что нужно и выводим данные на экран, чтобы вернуть их скрипту

	// Не забываем выходить
	wp_die();
}

Включаем кэширование для AJAX запросов

По умолчанию все AJAX запросы НЕ кэшируются браузером для этого PHP устанавливает специальные заголовки функцией nocache_headers().

Чаще всего AJAX запросы кэшировать и не надо, потому что они должны возвращать свежие данные, но бывают случаи когда такое кэширование может сэкономить ресурсы и увеличить скорость работы скрипта. Например, если у нас есть сложный фильтр товаров который юзеры используют постоянно. Тут было бы разумно кэшировать все результаты фильтра например на пару часов, все равно товары не добавляются с такой скоростью...

Как включить кэширование для указанных AJAX запросов смотрите во втором примере функции nocache_headers().

Отлавливаем баги, PHP ошибки

Проблемы могут возникнуть при AJAX запросе и появлении ошибок PHP. Заметки или сообщения могут изменить возвращаемый результат или вызвать ошибку javascript.

Дебаг (вывод ошибок на экран)

Вариант:

Как правило запросы отправляются с браузера в файл. Поэтому чтобы увидеть результат запроса, ошибку или что-либо еще, можно открыть панель разработчика, выбрать именно наш запрос среди многих и посмотреть что он вернул.

При этом в коде можно использовать привычные функции print_r() или var_dump(), чтобы увидеть что находится в нужных переменных.

Вариант: включаем показ ошибок в AJAX запросах

WordPress по умолчанию не показывает ошибки для AJAX запросов даже если константа WP_DEBUG включена! Видно это в коде функции wp_debug_mode().

Несмотря на это такой показ можно включить, ведь на рабочих проектах у нас все равно WP_DEBUG отключена и боятся нам нечего, а вот баги выловить это помогает на ура!

Чтобы включить показ ошибок при AJAX запроса, нужно вставить такой код в файл темы functions.php или в плагин. Но лучшее его вставить как можно раньше, чтобы видеть ранние ошибки, лучше всего в MU плагины...

if( WP_DEBUG && WP_DEBUG_DISPLAY && (defined('DOING_AJAX') && DOING_AJAX) ){
	@ ini_set( 'display_errors', 1 );
}

Вариант: вывод данных в лог файл

Если по ходу написания кода нужно заглянуть в переменную $myvar, то еще можно использовать такой код в обработчике ajax запроса:

error_log( print_r($myvar, true) );

В результате, в файл логов сервера (error.log) будет записано содержимое переменной $myvar. Так можно выполнить ajax, и заглянуть в лог.

Вариант: вывод PHP ошибок в лог файл

Чтобы выводить PHP заметки и ошибки в лог файл, нужно включить константу WP_DEBUG_LOG. Такой лог файл появится в папке wp-content.

Вариант:

Если не получается увидеть сообщение об ошибке и нужно работать в режиме разработчика, можно очистить буфер сразу перед возвратом данных:

ob_clean();
echo $whatever;
die();

После этого нужно посмотреть что возвращает запрос через дебаг браузера или как-то еще...

Вариант:

Также, для дебага можно воспользоваться инструментом FirePHP, который записывает ошибки в консоль браузера.

Ошибка при возвращении данных

Если AJAX запрос на в файл wp-admin/admin-ajax.php провалился, то будет возвращен ответ -1 или 0.

  • -1 - ошибка при проверке запроса. См. функцию check_ajax_referer()
  • 0 - обработка запроса вернула пустой результат
  • 0 - также возвращается по умолчанию во всех остальных случаях.

Плагины

Плагин AJAX Simply - добавляет класс, с помощью которого можно удобно и быстро писать AJAX запросы на стороне клиента и ответы на стороне сервера.

Качественный и надежный сервис по продвижению в Телеграмме предлагает совершить недорогую покупку подписчиков в группу. На сайте Вы найдете массу выгодных предложений с индивидуальными условиями для каждого сообщества. Например, Вы можете выбрать оптимальную скорость поступления ресурса, которая доходит до 1000 единиц в сутки. Успейте сделать заказ, пока на сайте действуют оптовые скидки.

92 комментария
Полезные - 10Вопросы - 2 Все
    Войти