Как делать AJAX-запросы в WordPress? Основы.

Эта статья ориентирована на начинающих пользователей. В ней мы не будем углубляться в теорию об AJAX, а сразу приступим к последовательному рассмотрению реализации этого метода обмена данными. Суть AJAX-запросов состоит в том, чтобы без перезагрузки страницы менять на ней информацию, то есть осуществлять обмен данными между клиентом (браузером) и сервером.

Задача: Без перезагрузки страницы отправить данные на сервер (сделать запрос), далее получить ответ, обработать и вывести на клиентской части (в браузере).

Решение: Прежде всего стоит отметить, что рассматриваемая последовательность действий и особенности работы с AJAX в этой статье справедливы только для WordPress и не будут соответственно работать в других CMS. Это нужно понимать. Что всё происходит в контексте CMS WordPress.

Последовательность

Прежде всего начнём с последовательности. Именно тут важно уловить принцип работы AJAX в WordPress.

  1. На странице происходит какое-то событие (клик, выбор варианта из выпадающего списка, отметка чек-бокса и т.п.)
  2. Это событие вызывает функцию JavaScript или на базе библиотеки jQuery.
  3. В эту функцию передаются данные и отправляются на сервер через HTTP-запрос.
  4. AJAX — это соединение технологий для асинхронной отправки данных (т.е. без перезагрузки страницы). AJAX-запрос можно выполнить на чистом JavaScript или через методы библиотеки jQuery. Так как jQuery входит в ядро WordPress принято писать запросы на базе её.
  5. Сервер получает наш запрос и обрабатывает данные — выполняет функции на уровне PHP и СУБД (база данных).
  6. Далее, сервер отправляет обработанные данные или просто какую-то служебную информацию браузеру в виде HTTP-ответа
  7. Функция (метод) библиотеки jQuery, которая изначально отправила запрос, получив ответ от сервера, может, например, вывести сообщение пользователю или обновить какую-то информацию на странице, естественно без её перезагрузки.

Примерно такая последовательность происходит при взаимодействии браузера (клиентская часть) с сервером по средствам AJAX. И сейчас с помощью кода мы восполним эту последовательность и посмотрим на неё в действии.

По классике создадим кнопочку и добавим её на страницу нашего сайта. Как создать кнопку в редакторе Gutenberg?

При создании кнопки задайте ей идентификатор. По ссылке выше есть полный пример добавления. Предположим ID нашей кнопки так и называется «knopochka». Теперь переходим к первому шагу — отслеживанию события. Отслеживать мы будем клик по этой кнопочке. Использовать AJAX мы будем на базе библиотеке jQuery при помощи метода .post()

И первый наш скрипт будет выглядеть вот так:

jQuery(document).ready(function ($) {
    $.post({
        url: url,
        data: data,
        success: success,
        dataType: dataType
    });
});

Давайте немного разберёмся в основных моментах. Самый главный момент это url — адрес куда будет отправлен наш запрос. В качестве данных (data) запроса у нас будет выступать строка или JSON объект.

Все AJAX-запросы для обработки в WordPress должны отправляться на специальный адрес wp-admin/admin-ajax.php. Естественно этот адрес на уровне jQuery получить не получится (хотя и можно его полностью прописать, но такой способ не будет универсальным). Для этого мы задействуем специальную функцию wp_localize_script() которая его и определит для дальнейшего использования.

Стоит отметить, что это необходимо делать для запросов в публичной части сайта, если вы разрабатываете функционал для Панели управления (“админка”) — приватной части сайта, то там уже необходимые переменные определены и вызывать wp_localize_script() перед вашим скриптом нет необходимости.

Подключение JS-скрипта

Создайте файлик с расширением js и подключите его на ваш сайт. Функция подключения скрипта из плагина может выглядеть примерно так:

function my_load_scripts( $hook ) {

	wp_register_script(
		'ajax_demo',
		get_template_directory_uri() . '/assets/js/public.js',
		array( 'jquery' ),
		filemtime( get_theme_file_path( 'assets/js/public.js' ) ), // Кэш?  Не-е, не слышали!
		array(
			//'in_footer' => true,
			//'strategy' => 'defer',
		)
	);

	// хак по борьбе с кешем)
	$my_js_ver = date( "ymd-Gis", filemtime( plugin_dir_path( __FILE__ ) . 'ajax-demo.js' ) );

	wp_register_script( 'ajax_demo', plugins_url( 'ajax-demo.js', __FILE__ ), array( 'jquery' ), $my_js_ver );
	wp_enqueue_script( 'ajax_demo' );
}

add_action( 'wp_enqueue_scripts', 'my_load_scripts' );

После подключения убедитесь в том, что ваш скрипт «инклудится» на странице. Так как мы передали одним из аргументов в функцию wp_enqueue_script подключения скрипта array(‘jquery’) — зависимость от библиотеки jQuery, то ожидаем, что наш скрипт будет подключён после jQuery. Это можно увидеть в примере ниже:

скрипт подключён

После этого нам нужно отследить событие по клику на нашу кнопку. Зная её идентификатор, мы смело можем добавить в наш файл уже осмысленный код:

jQuery(document).ready(function ($) {
    $("#knopochka").click(function () {
        alert("Это вызов обработчика по событию .click()");
    });
});

Теперь клик по нашей кнопке будет вызывать метод alert()

метод alert()

Отлично! Теперь переходим непосредственно к отправке AJAX-запроса и первым делом нам нужно получить URL обработчика. В этом нам поможет специальная функция wp_localize_script()

function my_load_scripts( $hook ) {

	// хак по борьбе с кешем)
	$my_js_ver = date( "ymd-Gis", filemtime( plugin_dir_path( __FILE__ ) . 'ajax-demo.js' ) );

	wp_register_script( 'ajax_demo', plugins_url( 'ajax-demo.js', __FILE__ ), array( 'jquery' ), $my_js_ver );
	wp_localize_script( 'ajax_demo', 'demo_ajax_object',
		array(
			'ajaxurl'   => admin_url( 'admin-ajax.php' ),
			'demo_id'  => get_the_ID(),
			'data_demo' => 'value demo',
		)
	);

	wp_enqueue_script( 'ajax_demo' );
}

add_action( 'wp_enqueue_scripts', 'my_load_scripts' );

wp_localize_script() отработает в том случае, если зарегистрированный скрипт будет подключен. Наш скрипт зарегистрирован под идентификатором «ajax_demo», соответственно первым аргументом мы эту зависимость и указали функции wp_localize_script(), ну а следующий аргумент — это название объекта «demo_ajax_object», в котором будут находится данные в виде «ключ:значение«:

  • ‘ajaxurl’ который будет передавать полный УРЛ на файл wp-admin/admin-ajax.php для обработки AJAX-запросов
  • ‘demo_id’ — «айдишник» текущей страницы
  • ‘data_demo’ -и просто для примера какие-то произвольные данные

Если вы всё сделали правильно, то должны увидеть перед своим скриптом выполнение этой функции, где уже определенны нужные нам данные, которые в дальнейшем мы можем задействовать в нашем скрипте.

Вернёмся к нашему скрипту JS и добавим в него часть ранее рассмотренного кода:

jQuery(document).ready(function ($) {
    $("#knopochka").click(function () {
        $.post({
            url: demo_ajax_object.ajaxurl,
            data: {
                'action': "",
                'page_id': demo_ajax_object.demo_id,
                'demo_text': demo_ajax_object.data_demo,
            },
        });
    });
});

Я думаю код не нуждается в подробных комментариях. Мы просто получаем данные из ранее созданного объекта demo_ajax_object.

Единственное новое тут это ‘action’. Здесь мы должны будем указать функцию, которая будет обрабатывать наши данные.

Предположим, что по клику мы хотим получать заголовок текущей страницы. Назовем нашу функцию-обработчик на стороне PHP — «demo_get_title_by_id» и укажем её значением к ключу

‘action’: ‘demo_get_title_by_id’,

Если придерживаться плана, который был определён последовательно в начале статьи, то мы уже находимся на 3-ем шаге

Передача данных на сервер и их дальнейшая обработка

«Встречать» наши данные в файле wp-ajax.php (туда куда мы их направляем) будут специальные функции, которые в WordPress называются:

  • wp_ajax_{$action} — срабатывает только для авторизованных на сайте (вошедших в систему) пользователей
  • wp_ajax_nopriv_{$action} — соответственно для не авторизованных, т.е. для обычных посетителей сайта

В отличие от wp_ajax_{$action}, глобальное свойство на уровне объекта JavaScript ajaxurl не будет определяться автоматически и должно быть включено вручную или с помощью wp_localize_script() с admin_url(‘admin-ajax.php’) в качестве определённых данных (что собственно и было сделано выше).

https://developer.wordpress.org/reference/hooks/wp_ajax_nopriv_action/

Наш код дополнится следующими функциями: первые две это для того чтобы наша функция-обработчик вызывалась для всех пользователей (обычных и авторизованных на сайте), а функция wp_die() которая находится в теле функции-обработчика вызывается для того чтобы не было никаких сюрпризов и после обработки AJAX-запроса происходило завершение, так сказать. И в теле функции я просто вывел строку с текстом, которую мы будем ожидать в качестве ответа от сервера.

add_action( "wp_ajax_demo_get_title_by_id", "demo_get_title_by_id" );
add_action( "wp_ajax_nopriv_demo_get_title_by_id", "demo_get_title_by_id" );

function demo_get_title_by_id() {

	echo "Это работает!";

	wp_die();

}

Допишем наш js скрипт. Добавим в него третий аргумент функцию обратного вызова которая выполняется в случае успешного выполнения запроса.

jQuery(document).ready(function ($) {
    $("#knopochka").click(function () {
        $.post({
            url: demo_ajax_object.ajaxurl,
            data: {
                'action': 'demo_get_title_by_id',
                'page_id': demo_ajax_object.demo_id,
                'demo_text': demo_ajax_object.data_demo,
            },
            success: function (response) {
                console.log('AJAX ответ : ',response);
            }
        });
    });
});

Если вы всё сделали правильно, то теперь по клику на кнопочку в консоли браузера вы должны увидеть результат работы функции-обработчика вашего AJAX-запроса 🙂

AJAX ответ :  Это работает!

Принимаем данные на сервере

Что ж, пришла пора встретить наши данные на уровне сервера в нашей PHP-функции. Сделать это можно при помощи $_GET, $_POST и $_COOKIE или общей переменной HTTP-запроса $_REQUEST, которая уже содержит в себе данные первых трёх.

В целях безопасности не рекомендуется использовать $_REQUEST (в связи с возможностью подлогом куки), а использовать ту глобальную переменную, которая соответствует вашему запросу.

add_action( "wp_ajax_demo_get_title_by_id", "demo_get_title_by_id" );
add_action( "wp_ajax_nopriv_demo_get_title_by_id", "demo_get_title_by_id" );

function demo_get_title_by_id() {

	$id = $_POST['page_id'];
	$txt = $_POST['demo_text'];

	echo $id . " " . $txt;

	wp_die();

}

Вот таким образом мы можем принять данные из нашего POST-запроса. Вот результат:

POST-запрос

Мы не будем затрагивать все аспекты безопасности (такие как чистка данных перед сохранением или выводом), а рассмотрим только один — защиту нашего запроса, чтобы быть уверенными, что обрабатываться на стороне PHP будет наш POST-запроса, который отправляется по клику на кнопку, а никакой-то там…

Защита запроса от ложного

Этот метод конечно же не панацея, но является хорошим тоном при отправке AJAX-запросов и не только. Это защита при помощи генерации уникального, одноразового значения, которое будет отправлено с клиента и проверено на стороне сервера.

Итак, создадим это уникальное значение в момент выполнения нашей функции wp_localize_script()

function my_load_scripts( $hook ) {

	// хак по борьбе с кешем)
	$my_js_ver = date( "ymd-Gis", filemtime( plugin_dir_path( __FILE__ ) . 'ajax-demo.js' ) );

	wp_register_script( 'ajax_demo', plugins_url( 'ajax-demo.js', __FILE__ ), array( 'jquery' ), $my_js_ver );
	wp_localize_script( 'ajax_demo', 'demo_ajax_object',
		array(
			'ajaxurl'   => admin_url( 'admin-ajax.php' ),
			'nonce'     => wp_create_nonce( 'demo_security' ),
			'demo_id'   => get_the_ID(),
			'data_demo' => 'value demo',
		)
	);

	wp_enqueue_script( 'ajax_demo' );
}

add_action( 'wp_enqueue_scripts', 'my_load_scripts' );

Мы добавили ‘nonce’ => wp_create_nonce( ‘demo_security’ ), соответственно, теперь в момент инициализации функции на странице будет это генерированное значение:

И теперь по цепочке передаём его дальше — в наш скрипт js, теперь он будет выглядеть вот так:

jQuery(document).ready(function ($) {
    $("#knopochka").click(function () {
        $.post({
            url: demo_ajax_object.ajaxurl,
            data: {
                'action': 'demo_get_title_by_id',
                'page_id': demo_ajax_object.demo_id,
                'demo_text': demo_ajax_object.data_demo,
                'nonce': demo_ajax_object.nonce,
            },
            success: function (response) {
                console.log('AJAX ответ : ', response);

            }
        });
    });
});

И на стороне сервера, на стороне «бэкэнд» мы должны проверить это значение с помощью специальной функции: check_ajax_referer(); в которую необходимо передать название нашего значения при создании (demo_security)

Вот такой вид примет наша функция-обработчик. В которую мы передали:

  1. Ключ, который был указан при создании nonce кода.
  2. Ключ, который указан в объекте отправляемым методом $.post (js файл)
function demo_get_title_by_id() {

	check_ajax_referer( 'demo_security', 'nonce' );

	$id  = $_POST['page_id'];
	$txt = $_POST['demo_text'];

	echo $id . " " . $txt;

	wp_die();

}

Примечание. Если определить название этих ключей, как ‘_ajax_nonce’ или ‘_wpnonce’, то второй аргумент можно не указывать, так как в POST-запросе WordPress будет уже брать значение из этих ключей.

И в завершении, давайте получим заголовок нашей текущей страницы и выведем его вместе с ссылкой на эту страницу, под нашей кнопкой, по которой был совершён клик.

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

function demo_get_title_by_id() {
	// Проверка
	check_ajax_referer( 'demo_security', 'nonce' );
	// Получаем айди страницы с которой идёт запрос
	$id = $_POST['page_id'];
	// Получаем заголовок (название) страницы по её айди
	$title = esc_html( get_the_title( $id ) );
	// Получаем постоянную ссылку на страницу по её названию
	$url = esc_url( get_permalink( get_page_by_title( $title ) ) );
	// вывод данных
	echo "Страница {$title} , ссылка {$url}";
	// завершаем выполнение
	wp_die();

}

В свою очередь, чтобы вывести данные под кнопкой нам необходимо дополнить наш js-код

jQuery(document).ready(function ($) {
    $("#knopochka").click(function () {
        $.post({
            url: demo_ajax_object.ajaxurl,
            data: {
                'action': 'demo_get_title_by_id',
                'page_id': demo_ajax_object.demo_id,
                'demo_text': demo_ajax_object.data_demo,
                'nonce': demo_ajax_object.nonce,
            },
            success: function (response) {
                console.log('AJAX ответ : ', response);
                $("#knopochka").after(function() {
                    return "<div>" + response + "</div>";
                });
            }
        });
    });
});

Результат по клику:

Результат по клику:

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