Программное создание постов в WordPress: от wp_insert_post до REST API
Основное решение: wp_insert_post в админке
Как программно создать пост в админке WordPress, используя стандартный обработчик admin-post-new.php?
Наиболее эффективное решение - вызов функции wp_insert_post() внутри хука admin_post_* или напрямую в коде темы/плагина. Этот метод обрабатывает все стандартные проверки прав, санитизацию и сохранение мета-полей.
add_action('admin_post_create_custom_post', 'handle_custom_post_creation');
function handle_custom_post_creation() {
if (!current_user_can('publish_posts')) {
wp_die('Недостаточно прав');
}
check_admin_referer('create_custom_post_action', 'nonce_field');
$post_data = array(
'post_title' => sanitize_text_field($_POST['title']),
'post_content' => wp_kses_post($_POST['content']),
'post_status' => 'publish',
'post_author' => get_current_user_id(),
'post_type' => 'post',
);
$post_id = wp_insert_post($post_data);
if (is_wp_error($post_id)) {
wp_redirect(add_query_arg('error', 'creation_failed', wp_get_referer()));
} else {
wp_redirect(admin_url('post.php?post=' . $post_id . '&action=edit&message=1'));
}
exit;
}
Wp admin options php (страница настроек в админке wordpress)
Пояснение шагов:
- Хук admin_post_create_custom_post срабатывает при отправке формы на
admin-post.php?action=create_custom_post. - Проверка прав
current_user_can('publish_posts'). - Проверка nonce через
check_admin_refererдля защиты от CSRF. - Санитизация полей заголовка и контента.
- Вызов
wp_insert_postс базовыми параметрами. - Обработка ошибок: если возвращается WP_Error, перенаправление с параметром ошибки.
- При успехе - редирект на страницу редактирования созданного поста.
Типичные ошибки и их решение:
- WP_Error с кодом 'invalid_post' - неправильно указан
post_typeилиpost_status. Проверьте регистр и наличие зарегистрированного типа записи. - Пост создаётся, но без контента - возможно, отсутствует санитизация. Убедитесь, что используется
wp_kses_postдля контента иsanitize_text_fieldдля заголовка. - Перенаправление не работает - после
wp_redirectобязательно вызывайтеexit;.
Варианты решений для разных сценариев
Как создать пост через REST API прямо из админки?
Если необходимо создавать посты асинхронно (через JavaScript), используется wp.apiFetch или обычный fetch к endpoint /wp/v2/posts. В админке WordPress это делается через AJAX с проверкой nonce.
jQuery.ajax({
url: wpApiSettings.root + 'wp/v2/posts',
method: 'POST',
beforeSend: function(xhr) {
xhr.setRequestHeader('X-WP-Nonce', wpApiSettings.nonce);
},
data: {
title: $('#post-title').val(),
content: $('#post-content').val(),
status: 'publish'
},
success: function(response) {
window.location.href = response.edit_link;
},
error: function(xhr, status, error) {
console.log('Ошибка:', xhr.responseJSON.message);
}
});
Admin post new php (создание нового поста в админке wordpress)
Возможные проблемы:
- Nonce не передан или устарел - используйте
wp_localize_scriptдля передачиwpApiSettings. - CORS-ошибки при использовании внешних запросов - встроенные эндпоинты админки не требуют CORS.
Как создать пост через XML-RPC (например, для удалённого управления)?
XML-RPC устарел, но всё ещё работает. В админке можно отправить запрос к xmlrpc.php с методом wp.newPost.
$client = new IXR_Client('https://example.com/xmlrpc.php');
$credentials = array(
'username' => 'admin',
'password' => 'password'
);
$post = array(
'post_title' => 'Заголовок',
'post_content' => 'Содержимое',
'post_status' => 'draft'
);
$result = $client->query('wp.newPost', 1, $credentials['username'], $credentials['password'], $post);
if ($client->isError()) {
echo 'Ошибка XML-RPC: ' . $client->getErrorCode() . ' - ' . $client->getErrorMessage();
} else {
echo 'Пост создан, ID: ' . $client->getResponse();
}
Wp login php action (действие логина wordpress)
Проблемы:
- Передача пароля в открытом виде - настоятельно не рекомендуется. Лучше использовать Application Passwords или REST API.
- Метод может быть отключён в настройках безопасности.
Как эмулировать стандартную форму admin-post-new.php через HTTP-запрос?
Можно отправить POST-запрос на admin-post.php с параметром action и всеми полями, как при ручном создании. Этот способ полностью повторяет логику админки.
$response = wp_remote_post(admin_url('admin-post.php'), array(
'body' => array(
'action' => 'create_custom_post',
'_wpnonce' => wp_create_nonce('create_custom_post_action'),
'title' => 'Новый пост',
'content' => 'Текст поста'
),
'cookies' => $_COOKIE // передача сессионных куков
));
Ошибки:
- Без нестатического nonce и куков аутентификации запрос не пройдёт проверку прав.
- Не рекомендуется для клиентского кода из-за необходимости передавать куки.
Расширенные примеры программного создания постов
Пример 1: Создание поста с мета-полями, таксономиями и миниатюрой через wp_insert_post
$post_id = wp_insert_post(array(
'post_title' => 'Расширенный пост',
'post_content' => 'Контент с [shortcode]',
'post_status' => 'publish',
'post_type' => 'post',
'post_category' => array(5, 12), // ID категорий
'tags_input' => array('тег1', 'тег2'),
'meta_input' => array(
'_custom_field' => 'значение',
'rating' => 4.5
)
));
// Добавление миниатюры (featured image)
$attachment_id = media_sideload_image('https://example.com/image.jpg', $post_id, 'Описание', 'id');
if (!is_wp_error($attachment_id)) {
set_post_thumbnail($post_id, $attachment_id);
}
Результат: Пост с ID 1234 создан с категориями, тегами, мета-полями и миниатюрой.
Пример 2: Создание поста асинхронно через AJAX с использованием wp_insert_post (в админке)
// В functions.php
add_action('wp_ajax_create_post_ajax', 'create_post_ajax_handler');
function create_post_ajax_handler() {
check_ajax_referer('ajax_create_nonce', 'nonce');
if (!current_user_can('edit_posts')) {
wp_send_json_error('Нет прав');
}
$post_id = wp_insert_post(array(
'post_title' => sanitize_text_field($_POST['title']),
'post_content' => wp_kses_post($_POST['content']),
'post_status' => 'publish',
));
if (is_wp_error($post_id)) {
wp_send_json_error($post_id->get_error_message());
} else {
wp_send_json_success(array('post_id' => $post_id, 'edit_url' => get_edit_post_link($post_id, '')));
}
}
JavaScript-часть:
jQuery.ajax({
url: ajaxurl,
method: 'POST',
data: {
action: 'create_post_ajax',
nonce: myAjax.nonce,
title: $('#post-title').val(),
content: $('#post-content').val()
},
success: function(response) {
if (response.success) {
window.location.href = response.data.edit_url;
} else {
alert('Ошибка: ' + response.data);
}
}
});
Пример 3: Создание поста через REST API с использованием Fetch (из админки)
const formData = new FormData();
formData.append('title', 'REST API пост');
formData.append('content', 'Создано через REST');
formData.append('status', 'draft');
fetch(wpApiSettings.root + 'wp/v2/posts', {
method: 'POST',
headers: {
'X-WP-Nonce': wpApiSettings.nonce,
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: 'REST API пост',
content: 'Создано через REST',
status: 'draft'
})
})
.then(response => response.json())
.then(data => {
if (data.id) {
console.log('Пост создан, ID:', data.id);
window.location.href = data.link + '&action=edit';
} else {
console.error('Ошибка:', data.message);
}
});
Пример 4: Пакетное создание постов с использованием wp_insert_post и транзакций (через $wpdb)
global $wpdb;
$wpdb->query('START TRANSACTION');
$success = true;
for ($i = 1; $i <= 10; $i++) {
$post_id = wp_insert_post(array(
'post_title' => "Пакетный пост $i",
'post_content' => "Содержание поста $i",
'post_status' => 'draft',
'post_author' => 1
));
if (is_wp_error($post_id)) {
$success = false;
break;
}
}
if ($success) {
$wpdb->query('COMMIT');
} else {
$wpdb->query('ROLLBACK');
}
Результат: 10 постов созданы в одной транзакции; при ошибке - откат всех изменений.
Пример 5: Обработка пользовательских полей и файлов (загрузка изображения через media_handle_upload)
if (!function_exists('wp_handle_upload')) {
require_once(ABSPATH . 'wp-admin/includes/file.php');
}
$uploadedfile = $_FILES['featured_image'];
$movefile = wp_handle_upload($uploadedfile, array('test_form' => false));
if ($movefile && !isset($movefile['error'])) {
$attachment = array(
'post_mime_type' => $movefile['type'],
'post_title' => sanitize_file_name($movefile['file']),
'post_content' => '',
'post_status' => 'inherit'
);
$attachment_id = wp_insert_attachment($attachment, $movefile['file'], $post_id);
require_once(ABSPATH . 'wp-admin/includes/image.php');
$attach_data = wp_generate_attachment_metadata($attachment_id, $movefile['file']);
wp_update_attachment_metadata($attachment_id, $attach_data);
set_post_thumbnail($post_id, $attachment_id);
}
Изображение загружено в медиатеку и прикреплено как миниатюра к созданному посту.