Вопрос или проблема
Я столкнулся со следующей проблемой при использовании WP_Query:
Я выполняю большой запрос и поэтому разбил его на партии, используя AJAX с увеличением смещения в каждом цикле. Проблема, с которой я сталкиваюсь, заключается в том, что весь процесс возвращает несколько дубликатов (посты из предыдущего цикла появляются в следующем) – причем не всегда одни и те же.
Запрос выглядит так:
$offset = $_POST['offset'];
$posts_per_page = 100;
$args = array(
'post_type' => array('player'),
'post_status' => 'publish',
'posts_per_page' => $posts_per_page,
'offset' => $offset,
'order' => 'DESC',
'ignore_sticky_posts' => 1,
//'fields' => 'ids',
'tax_query' => array(
array(
'taxonomy' => 'team',
'field' => 'term_id',
'terms' => [23,46,54,12,45],
),
)
);
$posts = new WP_Query($args);
Вышеприведенное выполняется повторно с использованием AJAX, при этом изменяется только $offset, который увеличивается каждый раз на 100 (равно предыдущему значению смещения плюс значению $posts_per_page), пока не будут запрошены все посты.
Пример возвращаемых ID постов:
1-й цикл: […,3606,3587,3588,3569,…]
2-й цикл: [3585,3586,3587,3588,3556,…]
3-й цикл: […,1594,2524,3026]
4-й цикл: [2524,3026,3009,…]
и так далее.
Любая помощь с этим будет весьма признательна.
Похожие проблемы, которые я нашел в интернете, но которые не предложили работающего для меня решения:
https://wordpress.org/support/topic/ajax-load-more-returning-random-duplicates/
WP_Query offset is returning post from prevois loop
Ответ или решение
Ваша проблема с использованием WP_Query и AJAX связана с тем, что вы получаете дублирующиеся посты при увеличении offset в ваших запросах. Рассмотрим это подробнее и предложим возможные решения с использованием методологии TEA (Теория, Пример, Применение).
Теория
Основная цель использования WP_Query с offset — это разбить большой набор данных на более управляемые части для отображения и загрузки через AJAX. Параметр offset в WP_Query используется для сдвига начальной точки выборки постов в базе данных, позволяя, например, избежать повторного запроса уже загруженных данных.
Однако, проблема, с которой вы столкнулись, связана с несовершенством самого механизма offset, который может вызвать дублирование постов. Дело в том, что при использовании offset WordPress выполняет SQL-запрос с конструкцией OFFSET, что, в свою очередь, может привести к изменению порядка постов из-за отсутствия точной сортировки или внезапных изменений в базе данных (например, добавление или удаление постов между запросами).
Пример
Рассмотрим ваш код подробнее:
$offset = $_POST['offset'];
$posts_per_page = 100;
$args = array(
'post_type' => array('player'),
'post_status' => 'publish',
'posts_per_page' => $posts_per_page,
'offset' => $offset,
'order' => 'DESC',
'ignore_sticky_posts' => 1,
'tax_query' => array(
array(
'taxonomy' => 'team',
'field' => 'term_id',
'terms' => [23,46,54,12,45],
),
)
);
$posts = new WP_Query($args);
Первый запрос возвращает посты с ID, например, 3606, 3587, 3588, 3569, второй запрос при увеличенном offset на 100 возвращает 3585, 3586, 3587, 3588 и так далее. Как видно, посты 3587 и 3588 присутствуют в обоих результирующих наборах, что свидетельствует о повторениях.
Применение
Решение 1: Использование post__not_in
Одним из решений является использование параметра post__not_in
, чтобы исключить конкретные посты, которые уже были загружены, из следующего запроса. Вам нужно будет вести учет ID постов, которые вы уже получили, и добавлять их в массив для исключений:
$loaded_posts = $_POST['loaded_posts']; // Массив ID постов, которые были уже загружены
$args = array(
'post_type' => array('player'),
'post_status' => 'publish',
'posts_per_page' => $posts_per_page,
'offset' => $offset,
'order' => 'DESC',
'ignore_sticky_posts' => 1,
'post__not_in' => $loaded_posts,
'tax_query' => array(
array(
'taxonomy' => 'team',
'field' => 'term_id',
'terms' => [23,46,54,12,45],
),
)
);
Решение 2: Постраничная пагинация
Если вы можете изменить логику, вы могли бы заменить offset на paged
, что позволяет избежать ряда проблем с дублированием:
$paged = $_POST['paged']; // Номер страницы, которую необходимо загрузить
$args = array(
'post_type' => array('player'),
'post_status' => 'publish',
'posts_per_page' => $posts_per_page,
'paged' => $paged,
'order' => 'DESC',
'ignore_sticky_posts' => 1,
'tax_query' => array(
array(
'taxonomy' => 'team',
'field' => 'term_id',
'terms' => [23,46,54,12,45],
),
)
);
$posts = new WP_Query($args);
Решение 3: Использование уникальных идентификаторов
Еще одним подходом может быть создание уникальных идентификаторов (например, временных меток публикации) вместо использования offset для определения начальной точки следующей загрузки:
$last_post_date = $_POST['last_post_date']; // Дата или другой уникальный параметр для последнего загруженного поста
$args = array(
'post_type' => array('player'),
'post_status' => 'publish',
'posts_per_page' => $posts_per_page,
'date_query' => array(
'before' => $last_post_date, // Посты, опубликованные до предыдущей даты
),
'order' => 'DESC',
'ignore_sticky_posts' => 1,
'tax_query' => array(
array(
'taxonomy' => 'team',
'field' => 'term_id',
'terms' => [23,46,54,12,45],
),
)
);
$posts = new WP_Query($args);
Таким образом, решая проблему дублирования с помощью вышеописанных стратегий, вы обеспечите более точное и стабильное извлечение данных при помощи WP_Query в контексте AJAX запросов. Выбирайте решение в зависимости от конкретных технических ограничений и требований.