На сайте с большим количеством образовательных курсов часто возникает задача массового импорта данных. Ручное добавление каждого курса через админку WordPress — неэффективно и занимает много времени. В этой статье разберём, как создать надёжный и масштабируемый импорт курсов с использованием AJAX и REST API WordPress.
Особенности массового импорта курсов в WordPress
Перед тем как приступить к технической реализации, важно понять, с какими проблемами можно столкнуться при импорте большого объёма данных:
- Временные ограничения PHP и сервера. Импорт больших файлов за один запрос может привести к тайм-аутам.
- Нагрузка на базу данных. Многочисленные операции вставки данных могут замедлить работу сайта.
- Валидация и обработка ошибок. Нужно корректно обрабатывать повреждённые или некорректные данные.
- Обновление уже существующих курсов. Нужно уметь распознавать дубликаты и обновлять их, а не создавать новые записи.
Для решения этих задач оптимально разбить импорт на несколько AJAX-запросов, которые будут поэтапно загружать данные и создавать записи в WordPress.
Создание REST API endpoint для обработки импорта курсов
Первый шаг — создать собственный REST API endpoint, который будет принимать часть данных и создавать или обновлять курсы. Предположим, что у вас есть кастомный тип записи course для курсов.
Добавим функцию в файл functions.php вашей темы или в отдельный плагин:
function wpfreecourses_register_import_endpoint() {
register_rest_route('wpfreecourses/v1', '/import-courses', array(
'methods' => 'POST',
'callback' => 'wpfreecourses_handle_import_courses',
'permission_callback' => function () {
return current_user_can('edit_posts');
},
));
}
add_action('rest_api_init', 'wpfreecourses_register_import_endpoint');
function wpfreecourses_handle_import_courses(WP_REST_Request $request) {
$courses = $request->get_param('courses');
if (!is_array($courses)) {
return new WP_REST_Response(array('error' => 'Invalid data format'), 400);
}
$results = [];
foreach ($courses as $course) {
// Проверяем обязательные поля
if (empty($course['title']) || empty($course['content'])) {
$results[] = array('status' => 'error', 'message' => 'Missing title or content');
continue;
}
// Проверяем, есть ли курс с таким названием
$existing = get_page_by_title($course['title'], OBJECT, 'course');
if ($existing) {
// Обновляем существующий курс
$post_id = $existing->ID;
wp_update_post(array(
'ID' => $post_id,
'post_content' => $course['content'],
));
$results[] = array('status' => 'updated', 'id' => $post_id);
} else {
// Создаём новый курс
$post_id = wp_insert_post(array(
'post_title' => $course['title'],
'post_content' => $course['content'],
'post_status' => 'publish',
'post_type' => 'course',
));
if (is_wp_error($post_id)) {
$results[] = array('status' => 'error', 'message' => $post_id->get_error_message());
} else {
$results[] = array('status' => 'created', 'id' => $post_id);
}
}
}
return $results;
}Данный endpoint принимает массив курсов, каждый из которых содержит заголовок и содержание. Если курс с таким заголовком уже есть, происходит обновление, иначе создаётся новый.
Организация AJAX-запросов для поэтапной загрузки данных
Для обхода ограничений по времени и памяти удобно разбивать импорт на части. В фронтенде можно реализовать загрузку JSON-файла с курсами и отправлять данные порциями по 10–20 записей.
Пример простого JavaScript-кода для отправки данных частями:
function wpfreecourses_importCourses(courses) {
let chunkSize = 20;
let index = 0;
function sendChunk() {
let chunk = courses.slice(index, index + chunkSize);
if (chunk.length === 0) {
console.log('Импорт завершён');
return;
}
fetch('/wp-json/wpfreecourses/v1/import-courses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': wpfreecourses.nonce
},
body: JSON.stringify({courses: chunk})
})
.then(response => response.json())
.then(data => {
console.log(data);
index += chunkSize;
sendChunk();
})
.catch(err => console.error('Ошибка:', err));
}
sendChunk();
}Важно передавать nonce для защиты REST API от CSRF-атак. Nonce можно сгенерировать и передать скрипту через wp_localize_script.
Пример структуры JSON для импорта курсов
Для успешной работы API нужно подготовить данные в формате:
[
{
"title": "Курс по WordPress для начинающих",
"content": "Подробное описание курса..."
},
{
"title": "Продвинутый курс по PHP",
"content": "Материалы для разработчиков..."
}
]<Такую структуру можно экспортировать из CSV или другой системы, преобразовав в JSON.
Настройка пользовательского типа записи и метаполей для курсов
Если у вас ещё нет кастомного типа записи course, можно зарегистрировать его так:
function wpfreecourses_register_post_type() {
register_post_type('course', array(
'labels' => array(
'name' => 'Курсы',
'singular_name' => 'Курс',
),
'public' => true,
'has_archive' => true,
'supports' => array('title', 'editor', 'thumbnail'),
'show_in_rest' => true,
));
}
add_action('init', 'wpfreecourses_register_post_type');Для хранения дополнительных данных, например цены или длительности, используйте метаполя. Их можно добавлять программно или через плагины, например Clearfy Pro.
Рекомендации по оптимизации и безопасности
Для успешного массового импорта важно соблюдать несколько правил:
- Обрабатывать ошибки и логировать результаты. Добавляйте логи, чтобы не потерять информацию о неудачных записях.
- Использовать транзакции базы данных при необходимости. Чтобы избежать частичной записи данных.
- Ограничивать права доступа к импорту. Только администраторы или редакторы должны иметь возможность запускать импорт.
- Проверять и фильтровать входящие данные. Чтобы избежать внедрения вредоносного кода.
Если у вас большая база курсов, можно дополнительно кешировать результаты, например, с помощью ABC Pagination для удобного отображения списка.