Программное создание постов в WordPress: от wp_insert_post до REST API

Раздел: PHP -> Администрирование WordPress

Основное решение: 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)

Пояснение шагов:

  1. Хук admin_post_create_custom_post срабатывает при отправке формы на admin-post.php?action=create_custom_post.
  2. Проверка прав current_user_can('publish_posts').
  3. Проверка nonce через check_admin_referer для защиты от CSRF.
  4. Санитизация полей заголовка и контента.
  5. Вызов wp_insert_post с базовыми параметрами.
  6. Обработка ошибок: если возвращается WP_Error, перенаправление с параметром ошибки.
  7. При успехе - редирект на страницу редактирования созданного поста.

Типичные ошибки и их решение:

  • 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);
}
Изображение загружено в медиатеку и прикреплено как миниатюра к созданному посту.

Создание нового поста в админке WordPress - comments

En
Admin post new php (php)