AJAX в WordPress плагинах: реальный пример из практики

Показывать справа: 0

При разработке плагинов для WordPress AJAX используется практически в каждом более-менее сложном проекте: личные кабинеты, формы, динамический контент, фильтры, действия без перезагрузки страницы.

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

Где применяется AJAX в плагинах

  • Личные кабинеты пользователей
  • Обработка форм без перезагрузки
  • Работа с тарифами, заказами
  • Динамическая подгрузка данных
  • Интерактивные интерфейсы

Структура вашего плагина

Хорошая практика — организовывать код плагина. Пример такой структуры:

your-plugin-name/
├── your-plugin-name.php (главный файл)
├── lib/
│   ├── ajax.php        (класс для базовой обработки AJAX)
│   └── events/
│       ├── ajaxs/      (отдельные файлы для каждого AJAX действия)
│       │   ├── dct_add_rate.php
│       │   └── ...
│       └── ajaxs.php   (файл для инклюдов и регистрации)
└── asset/
    └── js/
        └── script.js

Базовая структура плагина

В главном файле your-plugin-name.php задаю путь:


define('DCT_DIR', WP_PLUGIN_DIR .'/' . str_replace(basename(__FILE__), '', plugin_basename(__FILE__)));

Подключаю библиотеку AJAX:


require_once DCT_DIR . '/lib/ajax.php';

Абстрактный класс для обработки AJAX

Чтобы не дублировать код, используется базовый класс (/lib/ajax.php):


abstract class ajax_hand_dct {

    function __construct($action_name) {
        $this->init_hooks($action_name);
    }

    public function init_hooks($action_name) {
        add_action('wp_ajax_'.$action_name, array($this,'callback'));
        add_action('wp_ajax_nopriv_'.$action_name, array($this,'callback_nopriv'));
    }

    public function callback_nopriv() {
        $this->callback();
    }

    abstract public function callback();
}

Такой подход позволяет быстро добавлять новые AJAX-обработчики без копирования логики.

Динамическое подключение обработчиков

Подключение файлов по action (/lib/ajaxs.php):


$action = isset($_REQUEST['action']) ? sanitize_text_field($_REQUEST['action']) : '';

$filepath = DCT_DIR . '/lib/events/ajaxs/';

if (is_file($filepath . $action . ".php")) {
    require_once $filepath . $action . ".php";
}

Пример реального AJAX обработчика

Этот код находится в файле, например: DCT_DIR . '/lib/events/ajaxs/dct_add_rate.php'




class dct_add_rate extends ajax_hand_dct {

    // Не забудьте вызвать конструктор родителя, если он есть,
    // или просто создать экземпляр, передав действие.
    // Обычно это делается так: new dct_add_rate('dct_add_rate');
    // Если конструктор в базовом классе вызывается, как здесь:
    function __construct() {
        parent::__construct('dct_add_rate'); // 'dct_add_rate' - это значение для 'action' в JS
    }


    function callback() {
        global $wpdb;

        // Предполагается, что lib/rate.php содержит нужные классы/функции
        // require_once DCT_DIR . 'lib/rate.php';

        $status = 1; // 1 - успех, 0 - ошибка
        $error = '';
        $html = '';
        $fled = array(); // Массив для возвращаемых данных (например, ID новой записи)
        $mess_fled = array(); // Массив сообщений по конкретным полям
        $link = ''; // Ссылка для редиректа

        // --- Безопасность: Проверка Nonce ---
        // Предполагаем, что nonce передается через POST
        if ( !isset( $_POST['_ajax_nonce'] ) || !wp_verify_nonce( $_POST['_ajax_nonce'], 'dct_ajax_nonce_action' ) ) {
            wp_send_json_error( array( 'message' => 'Ошибка безопасности: проверьте ваш запрос.' ) );
        }

        // --- Получение данных ---
        $rate_id = isset($_POST['rate_id']) ? intval($_POST['rate_id']) : 0;

        // --- Валидация ---
        if (empty($rate_id)) {
            $status = 0;
            $error = 'Не выбран тариф';
        }

        // --- Проверка авторизации (если требуется) ---
        if ( !is_user_logged_in() ) {
            // Если действие требует авторизации, но пользователь не вошел
            // $status = 0;
            // $error = 'Для выполнения этого действия необходима авторизация.';
            // Или просто выйти, если это не требуется всегда
            // wp_send_json_error( array( 'message' => 'Вы должны быть авторизованы.' ) );
        }


        if ($status == 1) {
            $user = wp_get_current_user();
            $user_id = $user->ID;

            // здесь основная логика
            // Пример: добавление в базу данных
            // $result = $wpdb->insert('wp_dct_rates', array('user_id' => $user_id, 'rate_id' => $rate_id, 'timestamp' => current_time('mysql')), array('%d', '%d', '%s'));
            // if ($result) {
            //     $new_row_id = $wpdb->insert_id;
            //     $fled['new_id'] = $new_row_id;
            //     $message = 'Тариф успешно добавлен!';
            // } else {
            //     $status = 0;
            //     $message = 'Ошибка при добавлении тарифа.';
            // }

            // Пример получения ссылки, если она нужна
            // $page_kab_id = DCT::get_option_web('page_kab'); // Пример функции из вашего плагина
            // if ($page_kab_id) {
            //     $link = get_permalink($page_kab_id);
            // }

        }

        // Формируем объект ответа
        $options = array(
            "fled" => $fled, // Возвращаемые данные
            "link" => $link, // Ссылка для редиректа
            "mess_fled" => $mess_fled, // Сообщения по полям
            "message" => $error, // Общее сообщение (часто используется для ошибок)
            "html" => $html, // HTML для вставки на страницу
            "status" => $status, // Статус операции
        );

        // Отправляем JSON ответ.
        // wp_send_json_success($options); // Используйте, если все прошло успешно
        // wp_send_json_error($options); // Используйте, если произошла ошибка

        // В вашем примере была только wp_send_json_success, оставим так,
        // но в реальном проекте стоит различать успешные и ошибочные ответы.
        // Если $status == 0, лучше использовать wp_send_json_error.
        if ($status == 1) {
             wp_send_json_success($options);
        } else {
             wp_send_json_error($options);
        }
    }
}

// Создание экземпляра класса для регистрации AJAX обработчика.
// Важно, чтобы 'dct_add_rate' совпало с $action в JS и с названием файла.
new dct_add_rate();

Передача переменных в JavaScript

Для передачи PHP-переменных (например, `admin-ajax.php` URL) в JavaScript используется `wp_head` или `wp_localize_script`.


function js_variables_dct(){
    echo '<script type="text/javascript">
        var ajax_url_web = "'.admin_url('admin-ajax.php').'";
        var URL_PAGE = "'.get_permalink().'";
        var URL_ASSET = "'.DCT_URL.'asset/";
        // Если вам нужен nonce, его также можно передать здесь
        // var _ajax_nonce = "'.wp_create_nonce('dct_ajax_nonce_action').'";
    </script>';
}
add_action('wp_head','js_variables_dct');

Пример AJAX запроса на стороне JS

Использование `jQuery.ajax` для отправки данных.


// Предполагается, что mdata содержит все необходимые параметры, включая 'action' и nonce.
// Пример:
// var mdata = {
//     action: 'dct_add_rate', // Действие, которое соответствует 'wp_ajax_dct_add_rate'
//     rate_id: 123,
//     _ajax_nonce: _ajax_nonce // Полученный из PHP
// };

jQuery.ajax({
    url: ajax_url_web, // Переменная, полученная из PHP
    data: mdata, // Данные для отправки
    dataType: 'json', // Ожидаем JSON ответ
    type: 'POST', // Метод запроса

    beforeSend: function() {
        // Показываем индикатор загрузки
        console.log('Отправка данных...');
        // Например: jQuery('#loading-indicator').show();
    },

    success: function (res) {
        console.log('Ответ сервера:', res);
        // res будет объектом, содержащим 'success' (boolean) и 'data' (то, что вернул wp_send_json_success/error)
        if (res.success) {
            // Обработка успешного ответа
            if (res.data && res.data.message) {
                alert('Успех: ' + res.data.message);
            }
            if (res.data && res.data.html) {
                jQuery('#some-container').html(res.data.html);
            }
            if (res.data && res.data.link) {
                window.location.href = res.data.link; // Перенаправление
            }
        } else {
            // Обработка ошибки
            if (res.data && res.data.message) {
                alert('Ошибка: ' + res.data.message);
            } else {
                alert('Произошла неизвестная ошибка.');
            }
        }
    },

    error: function(jqXHR, textStatus, errorThrown) {
        // Обработка сетевых ошибок или ошибок сервера
        console.error('AJAX Error:', textStatus, errorThrown);
        alert('Произошла ошибка при выполнении запроса.');
    },

    complete: function() {
        // Действия, выполняемые после завершения запроса (успех или ошибка)
        console.log('Запрос завершен.');
        // Например: jQuery('#loading-indicator').hide();
    }
});

Что важно учитывать

  • Всегда валидировать входящие данные на стороне сервера.
  • Использовать `sanitize_*` функции для очистки данных.
  • Проверять авторизацию пользователя, если действие требует прав.
  • Структурировать код: использовать классы, отдельные файлы для каждого AJAX-действия.
  • Всегда использовать Nonce для защиты от CSRF-атак.
  • Предоставлять обратную связь пользователю (индикаторы загрузки, сообщения об успехе/ошибке).

Разработка и доработка WordPress плагинов

Если вам нужно реализовать подобную архитектуру или разработать плагин под задачи бизнеса:

Разработка на WordPress
Доработка WordPress

Заключение

AJAX — ключевой инструмент современной разработки на WordPress. Грамотная архитектура позволяет масштабировать проект и упрощает поддержку.

Заказать разработку

Покупка готового скрипта joomla 3

или просто напишите в телеграмм https://t.me/webalan