Прием и обработка POST в WordPress на PHP
Обработка POST данных в админке WordPress
При создании собственных страниц настроек, форм обратной связи или любых других функциональных элементов в административной панели WordPress возникает необходимость обработать данные, отправленные методом POST. Система предоставляет несколько проверенных способов для этого. Ниже рассмотрены наиболее популярные подходы с примерами кода и указанием типичных ошибок.
Как обработать POST запрос от формы в админке с помощью admin_post?
Основной способ - использовать хук admin_post_{action}. WordPress автоматически вызывает зарегистрированную функцию, когда запрос приходит на admin-post.php с параметром action, равным указанному вами.
Пример регистрации обработчика:
add_action('admin_post_save_my_settings', 'handle_save_my_settings');
function handle_save_my_settings() {
// Проверка nonce
if (!isset($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'], 'my_settings_nonce')) {
wp_die('Ошибка безопасности');
}
// Проверка прав
if (!current_user_can('manage_options')) {
wp_die('Недостаточно прав');
}
// Обработка данных
$value = sanitize_text_field($_POST['my_option']);
update_option('my_option', $value);
// Редирект с сообщением
wp_redirect(add_query_arg('message', 'saved', wp_get_referer()));
exit;
}
Wp login php action (действие логина wordpress)
Форма в админке:
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<?php wp_nonce_field('my_settings_nonce'); ?>
<input type="hidden" name="action" value="save_my_settings">
<input type="text" name="my_option" value="<?php echo esc_attr(get_option('my_option')); ?>">
<?php submit_button('Сохранить'); ?>
</form>
Admin post new php (создание нового поста в админке wordpress)
Типичные ошибки:
- Не указан параметр action в форме или он не совпадает с частью хука после admin_post_.
- Забыта проверка nonce - форма уязвима для CSRF.
- Использование wp_die без сообщения может запутать пользователя.
- Редирект без exit - выполнение скрипта продолжается.
Как выполнить асинхронный POST запрос через AJAX с помощью wp_ajax?
Для интерактивных элементов (например, кнопок управления без перезагрузки страницы) используется wp_ajax_{action} и wp_ajax_nopriv_{action} для неавторизованных пользователей.
Обработчик:
add_action('wp_ajax_my_async_action', 'handle_my_async_action');
function handle_my_async_action() {
check_ajax_referer('my_async_nonce', 'nonce');
if (!current_user_can('edit_posts')) {
wp_send_json_error('Нет прав');
}
$data = sanitize_text_field($_POST['some_data']);
// ... обработка
wp_send_json_success('Готово');
}
Wp admin options php (страница настроек в админке wordpress)
JavaScript:
jQuery(document).ready(function($) {
$('#my-button').on('click', function() {
$.post(ajaxurl, {
action: 'my_async_action',
nonce: '<?php echo wp_create_nonce('my_async_nonce'); ?>',
some_data: $('#my-field').val()
}, function(response) {
if (response.success) {
alert(response.data);
}
});
});
});
Admin post php (администрирование post в php)
Результат: асинхронная обработка без перезагрузки.
Ошибки: неправильное имя action, отсутствие ajaxurl (глобальная переменная в admin), забытая проверка nonce, отправка неверных типов данных.
Как обработать POST через REST API WordPress?
Более современный метод - создание собственного REST маршрута. Это особенно полезно для взаимодействия с внешними сервисами или одностраничными приложениями.
Пример регистрации маршрута:
add_action('rest_api_init', function() {
register_rest_route('myplugin/v1', '/data/', array(
'methods' => 'POST',
'callback' => 'handle_rest_post',
'permission_callback' => function() {
return current_user_can('manage_options');
}
));
});
function handle_rest_post($request) {
$params = $request->get_params();
$value = sanitize_text_field($params['value']);
update_option('rest_option', $value);
return new WP_REST_Response(array('status' => 'ok'), 200);
}
Запрос: POST к /wp-json/myplugin/v1/data с телом {"value": "text"} и заголовком X-WP-Nonce: <?php echo wp_create_nonce('wp_rest'); ?>.
Проблемы: неверный nonce, не настроены permission_callback (возвращает null - доступ открыт), не обработаны обязательные параметры, игнорирование кэширования.
Как обработать POST при сохранении стандартных настроек?
Если вы используете Settings API, WordPress автоматически обрабатывает POST при отправке формы, созданной с помощью settings_fields() и do_settings_sections(). Дополнительных обработчиков не требуется - функция, зарегистрированная как sanitize_callback, вызывается автоматически.
add_action('admin_init', function() {
register_setting('my_option_group', 'my_option', 'intval');
add_settings_section('my_section', 'Настройки', null, 'my-page');
add_settings_field('my_option', 'Поле', function() {
echo '<input type="number" name="my_option" value="' . esc_attr(get_option('my_option')) . '">';
}, 'my-page', 'my_section');
});
Форма выводится на странице:
<form method="post" action="options.php">
<?php settings_fields('my_option_group'); ?>
<?php do_settings_sections('my-page'); ?>
<?php submit_button(); ?>
</form>
Ошибки: неправильное имя группы в settings_fields, несоответствие имени опции и имени поля. Если sanitize_callback не возвращает значение, опция не сохраняется.
Расширенные примеры обработки POST в админке WordPress
Пример 1: Полная страница настроек с несколькими секциями и обработкой ошибок
Создается страница, на которой пользователь может изменить несколько опций. При сохранении выполняется валидация, и при ошибке отображается сообщение.
// Регистрация страницы настроек
add_action('admin_menu', function() {
add_options_page('Супер настройки', 'Супер настройки', 'manage_options', 'super-settings', 'render_super_settings_page');
});
// Обработчик POST через admin_post (не через Settings API, чтобы показать ручной контроль)
add_action('admin_post_save_super_settings', function() {
if (!isset($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'], 'super_settings_nonce')) {
wp_die('Ошибка проверки подлинности');
}
if (!current_user_can('manage_options')) {
wp_die('Недостаточно прав');
}
$errors = array();
$email = sanitize_email($_POST['admin_email']);
if (!is_email($email)) {
$errors[] = 'Некорректный email';
}
$number = intval($_POST['items_per_page']);
if ($number < 1 || $number > 100) {
$errors[] = 'Число должно быть от 1 до 100';
}
if (!empty($errors)) {
set_transient('super_settings_errors', $errors, 30);
wp_redirect(add_query_arg('error', '1', wp_get_referer()));
exit;
}
update_option('admin_email', $email);
update_option('items_per_page', $number);
wp_redirect(add_query_arg('message', 'saved', wp_get_referer()));
exit;
});
function render_super_settings_page() {
?>
<div class="wrap">
<h1>Супер настройки</h1>
<?php
if (isset($_GET['error'])) {
$errors = get_transient('super_settings_errors');
if ($errors) {
echo '<div class="error"><ul>';
foreach ($errors as $e) {
echo '<li>' . esc_html($e) . '</li>';
}
echo '</ul></div>';
delete_transient('super_settings_errors');
}
}
if (isset($_GET['message']) && $_GET['message'] == 'saved') {
echo '<div class="updated"><p>Настройки сохранены.</p></div>';
}
?>
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
<?php wp_nonce_field('super_settings_nonce'); ?>
<input type="hidden" name="action" value="save_super_settings">
<table class="form-table">
<tr>
<th><label for="admin_email">Email админа</label></th>
<td><input type="email" name="admin_email" id="admin_email" value="<?php echo esc_attr(get_option('admin_email')); ?>" class="regular-text"></td>
</tr>
<tr>
<th><label for="items_per_page">Элементов на странице</label></th>
<td><input type="number" name="items_per_page" id="items_per_page" value="<?php echo esc_attr(get_option('items_per_page', 10)); ?>" min="1" max="100"></td>
</tr>
</table>
<?php submit_button('Сохранить настройки'); ?>
</form>
</div>
<?php
}
Результат: страница настроек с валидацией, выводом ошибок и сообщением об успешном сохранении.
Пример 2: AJAX загрузка файла через POST с проверкой
Загрузка файла в админке без перезагрузки страницы. Используется wp_ajax и встроенная функция wp_handle_upload.
// Обработчик AJAX
add_action('wp_ajax_upload_custom_file', function() {
check_ajax_referer('upload_file_nonce', 'nonce');
if (!current_user_can('upload_files')) {
wp_send_json_error('Нет прав на загрузку файлов');
}
if (empty($_FILES['custom_file'])) {
wp_send_json_error('Файл не передан');
}
$uploaded = wp_handle_upload($_FILES['custom_file'], array('test_form' => false));
if (isset($uploaded['error'])) {
wp_send_json_error($uploaded['error']);
}
// Сохраняем URL в опцию
update_option('custom_uploaded_file', $uploaded['url']);
wp_send_json_success(array('url' => $uploaded['url'], 'file' => $uploaded['file']));
});
// JavaScript на странице админки
jQuery(document).ready(function($) {
$('#upload-button').on('click', function(e) {
e.preventDefault();
var fileData = new FormData();
fileData.append('action', 'upload_custom_file');
fileData.append('nonce', '<?php echo wp_create_nonce('upload_file_nonce'); ?>');
fileData.append('custom_file', $('#file-input')[0].files[0]);
$.ajax({
url: ajaxurl,
type: 'POST',
data: fileData,
contentType: false,
processData: false,
success: function(response) {
if (response.success) {
$('#preview').html('<img src="' + response.data.url + '" style="max-width:200px">');
} else {
alert('Ошибка: ' + response.data);
}
}
});
});
});
Результат: при нажатии на кнопку файл загружается на сервер, а в div #preview появляется превью.
Пример 3: REST маршрут с кастомной валидацией и отложенной обработкой
Создается маршрут, который принимает POST и ставит задачу в очередь (wp_schedule_single_event).
add_action('rest_api_init', function() {
register_rest_route('myapp/v1', '/queue-task', array(
'methods' => 'POST',
'callback' => 'handle_queue_task',
'permission_callback' => function() {
return current_user_can('manage_options');
},
'args' => array(
'task_type' => array(
'required' => true,
'validate_callback' => function($param) {
return in_array($param, array('email', 'report'));
}
),
'recipient' => array(
'required' => false,
'sanitize_callback' => 'sanitize_email'
)
)
));
});
function handle_queue_task($request) {
$type = $request->get_param('task_type');
$recipient = $request->get_param('recipient');
// Планируем задачу на выполнение через 5 минут
wp_schedule_single_event(time() + 300, 'my_custom_task_event', array($type, $recipient));
return new WP_REST_Response(array('scheduled' => true, 'eta' => 300), 200);
}
Результат ответа:
{
"scheduled": true,
"eta": 300
}
Данный подход снижает нагрузку на обработку тяжелых задач.
Пример 4: Экспорт данных через admin_post с потоковой передачей
Пользователь нажимает кнопку, инициируется загрузка CSV файла без лишних буферизаций.
add_action('admin_post_export_csv', function() {
if (!current_user_can('export')) {
wp_die('Нет прав');
}
if (!wp_verify_nonce($_GET['_wpnonce'], 'export_csv_nonce')) {
wp_die('Nonce error');
}
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="export.csv"');
$out = fopen('php://output', 'w');
fputcsv($out, array('ID', 'Имя', 'Email'));
$users = get_users();
foreach ($users as $user) {
fputcsv($out, array($user->ID, $user->display_name, $user->user_email));
}
fclose($out);
exit;
});
Форма-ссылка:
<a href="<?php echo wp_nonce_url(admin_url('admin-post.php?action=export_csv'), 'export_csv_nonce'); ?>" class="button">Скачать CSV</a>
При клике сразу начинается загрузка файла.