AJAX у WordPress: гайд з прикладами admin-ajax.php

Обкладинка гайду: AJAX у WordPress, практичний гайд з використання

Коротка відповідь: AJAX у WordPress дозволяє JavaScript обмінюватися даними з сервером без перезавантаження сторінки. Класичний спосіб: надіслати запит на admin-ajax.php з назвою action, і WordPress виконає PHP-функцію, прив’язану до хука wp_ajax_{action} (для авторизованих користувачів) або wp_ajax_nopriv_{action} (для відвідувачів). Функція повертає JSON, а скрипт оновлює сторінку. Сучасна альтернатива: власний ендпоінт REST API.

Розберемо все покроково, так, як досвідчений розробник пояснює стажеру: спершу ідея, потім мінімальний робочий приклад, потім безпека і наприкінці помилки, на які йде найбільше часу.

Що таке AJAX і навіщо він у WordPress?

AJAX розшифровується як Asynchronous JavaScript and XML, але сьогодні XML ніхто не надсилає. Ви відправляєте запит у фоні, отримуєте JSON і змінюєте частину сторінки. Типові випадки: живий пошук, кнопка «Завантажити ще», фільтрація товарів, відправлення форми без перезавантаження, голосування або лайк запису.

WordPress потрібна стандартна точка входу для таких запитів, бо PHP-код вашої теми чи плагіна не виконується, поки WordPress не завантажений. Ця точка входу: wp-admin/admin-ajax.php.

Як працює AJAX у WordPress?

  1. Браузер виконує JavaScript і надсилає POST-запит на admin-ajax.php з полем action.
  2. WordPress завантажується, перевіряє значення action і запускає відповідний хук: wp_ajax_my_action для авторизованих користувачів або wp_ajax_nopriv_my_action для відвідувачів.
  3. Ваша PHP-функція виконується, перевіряє безпеку, робить роботу і повертає JSON через wp_send_json_success() або wp_send_json_error(). Ці функції також зупиняють виконання скрипта.
  4. JavaScript отримує JSON і оновлює DOM.

Пастка для стажера: action це просто рядок, який ви вигадуєте самі. Це не назва функції WordPress. Якщо рядок у JavaScript і в add_action() відрізняється хоча б одним символом, нічого не спрацює.

Мінімальний приклад AJAX у WordPress

Зробимо невеликий живий пошук, який повертає заголовки підходящих записів. Він складається з трьох частин: підключити скрипт і передати йому адресу AJAX та nonce, обробити запит у PHP і викликати його з JavaScript.

Крок 1: підключіть скрипт і передайте адресу AJAX

На фронтенді WordPress не надає глобальної змінної ajaxurl, тому передайте її самі через wp_localize_script(). Додайте це у functions.php теми або в плагін:

add_action( 'wp_enqueue_scripts', function () {
    wp_enqueue_script(
        'my-ajax',
        get_template_directory_uri() . '/js/my-ajax.js',
        array(),
        '1.0',
        true
    );

    wp_localize_script( 'my-ajax', 'myAjax', array(
        'url'   => admin_url( 'admin-ajax.php' ),
        'nonce' => wp_create_nonce( 'my_ajax_nonce' ),
    ) );
} );

Крок 2: напишіть PHP-обробник

Зареєструйте одну функцію і для авторизованих користувачів, і для відвідувачів. Спершу перевірте nonce, потім очистіть вхідні дані, потім виконайте роботу:

add_action( 'wp_ajax_my_action', 'my_ajax_handler' );
add_action( 'wp_ajax_nopriv_my_action', 'my_ajax_handler' );

function my_ajax_handler() {
    check_ajax_referer( 'my_ajax_nonce', 'nonce' );

    $term = isset( $_POST['term'] ) ? sanitize_text_field( wp_unslash( $_POST['term'] ) ) : '';

    if ( '' === $term ) {
        wp_send_json_error( array( 'message' => 'Empty search term' ), 400 );
    }

    $query = new WP_Query( array(
        's'              => $term,
        'posts_per_page' => 5,
        'post_status'    => 'publish',
    ) );

    $items = array();
    foreach ( $query->posts as $post ) {
        $items[] = array(
            'title' => get_the_title( $post ),
            'url'   => get_permalink( $post ),
        );
    }

    wp_send_json_success( $items );
}

Крок 3: викличте його з JavaScript через fetch

Надішліть action, nonce і ваші дані як дані форми. Тіло URLSearchParams саме виставляє потрібний тип вмісту:

const form = document.querySelector('#search-form');
const list = document.querySelector('#results');

form.addEventListener('submit', async (event) => {
  event.preventDefault();

  const body = new URLSearchParams({
    action: 'my_action',
    nonce: myAjax.nonce,
    term: form.elements.term.value,
  });

  const response = await fetch(myAjax.url, { method: 'POST', body });
  const json = await response.json();

  if (!json.success) {
    console.error(json.data.message);
    return;
  }

  list.replaceChildren(
    ...json.data.map((item) => {
      const li = document.createElement('li');
      const a = document.createElement('a');
      a.href = item.url;
      a.textContent = item.title;
      li.append(a);
      return li;
    })
  );
});

Зверніть увагу: заголовки додаються через textContent, а не innerHTML. Ніколи не вставляйте дані із сервера на сторінку як сирий HTML, якщо ви їх не екранували.

Той самий запит на jQuery

Старі теми досі користуються jQuery. Ідея та сама, змінюється лише синтаксис. Для нового коду jQuery не потрібен:

jQuery.post( myAjax.url, {
  action: 'my_action',
  nonce: myAjax.nonce,
  term: 'wordpress'
} ).done( function ( response ) {
  console.log( response.data );
} );

Що можна зробити через AJAX у WordPress?

  • Живий пошук. Приклад вище, плюс debounce, щоб не надсилати запит на кожну літеру.
  • «Завантажити ще» і пагінація. Надсилаєте номер сторінки, виконуєте WP_Query з paged і повертаєте наступні записи.
  • Фільтри. Надсилаєте вибрані категорії чи атрибути й повертаєте відфільтрований список, наприклад у магазині на WooCommerce.
  • Форми. Відправляєте дані, не залишаючи сторінку, і показуєте повідомлення про успіх.
  • Вхід, голосування й лайки. Невеликі дії, що оновлюють один елемент.

Для «Завантажити ще» змінюються лише дані, які ви надсилаєте, і запит, який виконуєте:

$paged = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;

$query = new WP_Query( array(
    'post_status'    => 'publish',
    'posts_per_page' => 6,
    'paged'          => $paged,
) );

Як захистити AJAX-запити?

Кожен AJAX-обробник це відкриті двері у ваш сайт, тому ставтеся до нього відповідно. Чотири правила покривають більшість випадків:

  • Перевіряйте nonce через check_ajax_referer(). Він захищає від підроблених запитів. Це не авторизація, а на кешованій сторінці nonce може прострочитися.
  • Перевіряйте права через current_user_can() для всього, що змінює дані або показує приватну інформацію.
  • Очищуйте вхідні дані функціями на кшталт sanitize_text_field() і absint(), а вивід екранувати.
  • Не реєструйте хук nopriv для дій, які мають виконувати лише авторизовані користувачі. Якщо дія редагує чи видаляє щось, вона не повинна бути доступна відвідувачам.

AJAX чи REST API: що обрати?

admin-ajax.php досі працює і підходить для невеликих завдань у темах і плагінах. REST API краще для нового коду, який можуть викликати інші застосунки, для запитів, що кешуються, і для чистіших адрес та перевірок прав. Практична різниця: кожен виклик admin-ajax.php завантажує все середовище WordPress, тому на важкому сайті він може бути повільним.

REST-маршрут для того самого пошуку виглядає так. Зверніть увагу: permission_callback обов’язковий, і для публічного ендпоінта його задають явно:

add_action( 'rest_api_init', function () {
    register_rest_route( 'myplugin/v1', '/search', array(
        'methods'             => 'GET',
        'callback'            => 'my_rest_search',
        'permission_callback' => '__return_true',
        'args'                => array(
            'term' => array(
                'required'          => true,
                'sanitize_callback' => 'sanitize_text_field',
            ),
        ),
    ) );
} );
admin-ajax.phpREST API
Найкраще дляПростих дій у темі чи плагініНових функцій, публічних або кешованих даних, зовнішніх застосунків
БезпекаNonce і ваші власні перевіркиNonce (X-WP-Nonce) і permission_callback
ШвидкістьЩоразу завантажує весь WordPressТакож завантажує WordPress, але GET-запити легше кешувати
АдресаОдна адреса для всьогоОкрема адреса для кожного маршруту

Чому AJAX-запит у WordPress не працює?

Відкрийте інструменти розробника в браузері, перейдіть на вкладку Network і подивіться на запит до admin-ajax.php. Код статусу й відповідь підкажуть більшість того, що потрібно:

СимптомІмовірна причинаЩо перевірити
Відповідь 0 зі статусом 200Обробник виконався, але не зупинив скриптЗавершіть обробник через wp_send_json_success(), wp_send_json_error() або wp_die()
Відповідь 0 зі статусом 400Для цього action не зареєстровано хук, або action відсутнійТочно співставте рядок action і додайте хук wp_ajax_nopriv_ для відвідувачів
-1 або статус 403Перевірку nonce не пройдено, або запит заблокував плагін безпеки чи файрволПеревірте назву nonce, оновіть кешовані сторінки й подивіться правила плагіна безпеки
myAjax is not definedСкрипт не підключено або не передано даніПеревірте handle у wp_enqueue_script() і wp_localize_script()
Код обробника не виконуєтьсяКод пропускається під час AJAX-запитівadmin-ajax.php вважається адмінкою, тому код в умові ! is_admin() не завантажиться

Якщо запити повільні, подивіться, що робить обробник: важкі запити, зовнішні виклики та плагіни, що завантажуються на кожен запит. Про загальне прискорення читайте в матеріалі «Оптимізація швидкості сайту».

Часті запитання

Що таке admin-ajax.php у WordPress?

Це файл, який WordPress надає для обробки AJAX-запитів. Він завантажує WordPress, читає параметр action і виконує PHP-функцію, зареєстровану для нього.

У чому різниця між wp_ajax і wp_ajax_nopriv?

wp_ajax_{action} виконується для авторизованих користувачів, а wp_ajax_nopriv_{action} для відвідувачів без входу. Щоб підтримати обох, зареєструйте функцію на обох хуках.

Як отримати адресу AJAX на фронтенді?

Передайте її з PHP через wp_localize_script(), використавши admin_url( 'admin-ajax.php' ), як у прикладі вище. Не покладайтеся на глобальну змінну ajaxurl поза адмінкою.

Чи застарів admin-ajax.php?

Ні, він і далі підтримується. Для нових функцій, які можуть використовувати інші застосунки, зазвичай краще підходить REST API.

Чи потрібен jQuery для AJAX у WordPress?

Ні. Метод fetch() у браузері працює добре, а jQuery потрібен лише якщо ваша тема чи плагін уже від нього залежить.

Чи безпечний AJAX у WordPress?

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

Потрібна допомога з розробкою на WordPress?

Якщо вам потрібні кастомні функції, теми на WordPress або розробка сайту під ключ, опишіть задачу в кілька речень, і я відповім із запитаннями та орієнтиром. Telegram: t.me/dykyiivan, пошта: dykyiivan@outlook.com.

Обговорити проєкт

Читайте також