Вопрос или проблема
Хорошо, мне нужна помощь, и я не знаю, делаю ли я это правильно, но я хотел бы узнать, может ли сообщество направить меня в лучшую сторону.
Вот что происходит:
-
У меня есть
register_rest_route()
, который вызывает функцию (не включена в этот код). -
Я делаю вызов, чтобы получить заголовки конечной точки, где содержится общее количество страниц
$headers['headers']['x-wp-totalpages']
, которое равно 80. -
Затем я перебираю все страницы и вызываю wp_remote_get, чтобы получить 25 постов с каждой страницы.
-
После этого я просматриваю каждый пост из 25 постов и создаю посты на новом сайте.
Некоторые детали:
У меня есть 795 постов на сайте, которые содержат все данные. Когда я запускаю текущую функцию, она проходит через все 795 постов и фактически импортирует их, так что она частично работает, но есть ошибки.
Что я пытаюсь достичь:
Кто-нибудь знает, как я могу отформатировать эту функцию, чтобы мой параметр wp_remote_get()
$page
увеличивался только тогда, когда я захожу на конечную точку до $headers['headers']['x-wp-totalpages']
, а затем сбрасывался обратно на $page=1
, и не использовать цикл for, который автоматически проходит через все 80 страниц за один запрос?
Итак, у меня есть следующая функция:
public function get_posts_via_rest_api(): void
{
// Подключаем метод post_exists для конечных точек.
if (!is_admin()) {
require_once(ABSPATH . 'wp-admin/includes/post.php');
}
// Получаем заголовки REST API
$headers = wp_remote_head('https://website-im-getting-data-from.com/wp-json/wp/v2/posts');
// Начинаем с 1 страницы и проходим через все 80 страниц от x-wp-totalpages
for ($i = 1; $i <= $headers['headers']['x-wp-totalpages']; $i++) {
$response = wp_remote_get(
add_query_arg( [
'page' => $i,
'per_page' => 25,
'post_status' => 'publish',
], 'https://website-im-getting-data-from.com/wp-json/wp/v2/posts')
);
// Успешный ответ? Продолжаем.
if (wp_remote_retrieve_response_code($response) === 200) {
try {
$posts = json_decode(
wp_remote_retrieve_body($response),
false,
512,
JSON_THROW_ON_ERROR
);
} catch (Exception) {
return;
}
// Перебираем 25 постов с указанной страницы
foreach ($posts as $post) {
$current_post_id = post_exists($post->title->rendered);
if ($current_post_id === 0) {
$my_post = [
'post_type' => 'post',
'post_status' => 'pending',
'post_title' => wp_strip_all_tags($post->title->rendered),
'post_content' => wp_strip_all_tags($post->content->rendered),
'post_excerpt' => wp_strip_all_tags($post->excerpt->rendered),
'post_author' => 1,
'post_date' => $post->date,
];
// Вставляем пост.
$post_id = wp_insert_post($my_post);
wp_set_object_terms($post_id, 'Global', 'category');
wp_set_object_terms($post_id, 'Global', 'post_tag');
echo "ID: " . $post->id . " - Title: " . $post->title->rendered . " был импортирован.\n";
}
}
}
}
}
Вместо того чтобы получать первую страницу, а затем проходить по общему количеству страниц из переменной, лучше сохранить его как опцию и использовать второе значение, чтобы указать следующую страницу.
Таким образом, вы получаете номер следующей страницы, получаете ее, обрабатываете посты, затем обновляете параметры общих страниц, используя новый заголовок из этого запроса, добавляете 1 к опции следующей страницы и сохраняете ее. Если следующая страница больше, чем общее количество страниц, сбрасываете ее на 1.
Ответ или решение
Для того чтобы правильно обработать пагинацию при получении данных из REST API с помощью функции wp_remote_get()
в WordPress, мы можем использовать стратегию поэтапного выполнения запросов. Вместо однократного запроса, который обрабатывает все страницы, мы будем запрашивать данные поэтапно, увеличивая номер страницы после каждого успешного запроса и обновляя общее количество страниц на основе заголовков ответа.
Что мы собираемся сделать
- Инициализация: Начнем с установки параметров для хранения текущей страницы и общего количества страниц.
- Получение данных: Запросим данные с текущей страницы. Если запрос успешен, обработаем полученные записи.
- Обработка ответов: Обновим информацию о текущей странице и общем количестве страниц.
- Сохранение состояния: Сохраним состояние (текущую страницу) в опции WordPress, чтобы в следующем вызове функции продолжить с правильной страницы.
Пример кода с улучшенной логикой пагинации
Вот пример кода, который осуществляет вышеописанные шаги:
public function get_posts_via_rest_api(): void
{
// Подключение функций для работы с постами
if (!is_admin()) {
require_once(ABSPATH . 'wp-admin/includes/post.php');
}
// Получаем текущие значения из опций
$current_page = get_option('api_current_page', 1);
$total_pages = get_option('api_total_pages', 0);
// Получаем данные с текущей страницы
$response = wp_remote_get(
add_query_arg( [
'page' => $current_page,
'per_page' => 25,
'post_status' => 'publish',
], 'https://website-im-getting-data-from.com/wp-json/wp/v2/posts')
);
// Проверяем успешность запроса
if (is_wp_error($response)) {
error_log('Ошибка при работе с API: ' . $response->get_error_message());
return;
}
// Обновляем количество страниц на основе заголовков
$headers = wp_remote_retrieve_headers($response);
if (isset($headers['x-wp-totalpages'])) {
$total_pages = $headers['x-wp-totalpages'];
update_option('api_total_pages', $total_pages);
}
// Обрабатываем полученные данные
$posts = json_decode(wp_remote_retrieve_body($response), true);
foreach ($posts as $post) {
// Проверяем существует ли пост, если нет - создаем новый
$current_post_id = post_exists($post['title']['rendered']);
if ($current_post_id === 0) {
$my_post = [
'post_type' => 'post',
'post_status' => 'pending',
'post_title' => wp_strip_all_tags($post['title']['rendered']),
'post_content' => wp_strip_all_tags($post['content']['rendered']),
'post_excerpt' => wp_strip_all_tags($post['excerpt']['rendered']),
'post_author' => 1,
'post_date' => $post['date'],
];
// Вставка поста
$post_id = wp_insert_post($my_post);
wp_set_object_terms($post_id, 'Global', 'category');
wp_set_object_terms($post_id, 'Global', 'post_tag');
echo "ID: " . $post['id'] . " - Title: " . $post['title']['rendered'] . " has been imported.\n";
}
}
// Увеличиваем номер страницы или сбрасываем его
if ($current_page < $total_pages) {
$current_page++;
} else {
$current_page = 1; // Сброс до первой страницы
}
// Сохраняем обновленные значения
update_option('api_current_page', $current_page);
}
Комментарии к коду
-
Инициализация состояния: Мы используем
get_option()
для получения текущей страницы и общего количества страниц. Если ранее не было сохранено значения, мы устанавливаем значение по умолчанию. -
Запрос данных: Используем
wp_remote_get()
для запроса данных с текущей страницы. Обрабатываем ошибки, если они возникли. -
Обработка ответов: После успешного запроса обновляем общее количество страниц и обрабатываем полученные записи, добавляя новые посты только в случае их отсутствия в базе.
-
Управление пагинацией: Номер страницы увеличивается при каждом вызове, а если достигнут конец, сбрасываем его до 1.
Заключение
Этот подход обеспечивает более эффективное использование API и позволяет избежать проблем, связанных с превышением лимита запросов. Более того, использование опций для хранения текущего состояния позволяет выполнять функцию многократно, не теряя контекста между вызовами. Таким образом, вы получите надежную и стабильную реализацию для работы с пагинацией в WordPress REST API.