Повторяющиеся записи на странице архива или в блоке с последними постами обычно появляются не из-за одной ошибки, а из-за цепочки мелочей: лишний кастомный запрос, неправильный pre_get_posts, дублирующийся вывод в шаблоне или конфликт с плагином, который тоже меняет основной запрос. Внешне это выглядит просто — один и тот же пост показывается дважды. На практике важно понять, где именно возникает дубль: в SQL-запросе, в массиве постов или уже в HTML.
Ниже — рабочая схема, которая помогает не гадать, а быстро локализовать источник проблемы и исправить его без лишних правок в теме.
Как выглядит проблема и где искать источник дублей
Сначала стоит разделить сценарии. Если запись повторяется в ленте блога, причина часто в запросе или фильтре. Если дубль виден только в отдельном блоке темы, проблема обычно в шаблоне. Если посты дублируются после подключения плагина фильтрации, надо смотреть, не создаёт ли он дополнительный запрос поверх основного.
Типичные признаки
- одна и та же запись встречается дважды в
home.php,archive.phpили в блоке на главной; - в админке записи уникальны, а на фронтенде вывод повторяется;
- дубли появляются только для части рубрик, таксономий или страниц пагинации;
- после установки SEO- или фильтрующего плагина поведение меняется без правок темы.
Что проверить в первую очередь
- не вызывается ли один и тот же цикл дважды;
- не используется ли
query_posts()вместо отдельногоWP_Query; - нет ли фильтра
pre_get_posts, который меняет основной запрос без условий; - не добавляет ли тема записи вручную через массив, а затем ещё раз через стандартный цикл.
Диагностика: как понять, где именно появляется дубль
Самый быстрый способ — посмотреть, что реально возвращает запрос. Для этого не нужно сразу лезть в базу. Достаточно временно вывести ID записей и сравнить их с тем, что видно на странице.
<?php
// Временно вставьте в шаблон архива или в нужный шаблонный файл.
if ( have_posts() ) {
while ( have_posts() ) {
the_post();
echo '<p>ID: ' . get_the_ID() . ' — ' . esc_html( get_the_title() ) . '</p>';
}
}
?>Если ID уже повторяются в этом выводе, проблема в запросе. Если ID уникальны, а на странице всё равно виден дубль, значит запись выводится второй раз в другом месте шаблона — например, в сайдбаре, в хук-области темы или через блок.
Полезно также проверить, не вмешивается ли код в основной запрос. Для этого можно временно добавить логирование в pre_get_posts и посмотреть, какие условия срабатывают.
<?php
add_action( 'pre_get_posts', function( WP_Query $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
error_log( 'Main query: ' . print_r( $query->query_vars, true ) );
} );Если в логах видно, что фильтр срабатывает на архиве, главной и пагинации одинаково, а условия не ограничены, это уже кандидат на исправление.
Пошаговое решение без ломки шаблона
1. Не используйте query_posts()
Это частая причина неожиданных дублей и поломки пагинации. query_posts() перезаписывает глобальный запрос и часто создаёт побочные эффекты. Если нужен отдельный список записей, используйте WP_Query.
<?php
$posts = new WP_Query( array(
'post_type' => 'post',
'posts_per_page' => 6,
'post__not_in' => array( get_queried_object_id() ),
) );
if ( $posts->have_posts() ) {
while ( $posts->have_posts() ) {
$posts->the_post();
the_title( '<h2>', '</h2>' );
}
wp_reset_postdata();
}2. Ограничьте изменения основного запроса
Если вы меняете количество постов или исключаете рубрику через pre_get_posts, обязательно проверяйте контекст. Иначе фильтр начнёт работать там, где не должен: в админке, в поиске, на пагинации или в REST-запросах.
<?php
add_action( 'pre_get_posts', function( WP_Query $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( $query->is_home() ) {
$query->set( 'posts_per_page', 10 );
$query->set( 'category__not_in', array( 12 ) );
}
} );Здесь важно не просто задать параметры, а сделать это только для нужной страницы. Иначе вы получите побочные дубли в архиве, поиске или на странице блога.
3. Исключите повторный вывод в шаблоне
Иногда проблема не в запросе, а в том, что один и тот же блок подключён дважды: в шаблоне и через хук темы. Проверьте, не вызывается ли один и тот же partial в нескольких местах. Если блок должен появляться только один раз, вынесите его в отдельную функцию и подключайте централизованно.
<?php
function wpdebug_render_featured_posts() {
$q = new WP_Query( array(
'post_type' => 'post',
'posts_per_page' => 3,
'no_found_rows' => true,
) );
if ( ! $q->have_posts() ) {
return;
}
echo '<div class="featured-posts">';
while ( $q->have_posts() ) {
$q->the_post();
echo '<article>' . esc_html( get_the_title() ) . '</article>';
}
echo '</div>';
wp_reset_postdata();
}
Сравнение подходов: плагин, код или правка шаблона
| Подход | Когда уместен | Минус |
|---|---|---|
| Правка шаблона | Дубли только в одной области темы | Нужно понимать структуру темы |
Код через pre_get_posts | Нужно управлять основным запросом | Легко задеть лишние страницы без условий |
| Плагин для отладки | Нужно быстро увидеть SQL и хуки | Дополнительная нагрузка и лишние зависимости |
Если задача разовая, лучше сначала отладить кодом и логами. Плагин имеет смысл только как временный инструмент диагностики, а не как постоянное решение.
Проверка результата после исправления
После правки не ограничивайтесь визуальной проверкой главной страницы. Дубли часто всплывают только на пагинации, в рубриках или на мобильной версии темы.
- откройте главную, архив рубрики и страницу пагинации;
- сравните ID записей в HTML или через временный вывод;
- проверьте, не сломалась ли пагинация после изменения запроса;
- посмотрите
error_log, если добавляли временное логирование; - убедитесь, что один и тот же пост не приходит из двух разных блоков.
Если используете кэш, очистите его после проверки. Иначе можно принять старый HTML за результат новой правки.
Частые ошибки и как их исправить
Фильтр срабатывает везде
Причина — нет проверки is_main_query() или контекста страницы. Исправление: ограничьте фильтр конкретным архивом, поиском или главной.
Пагинация показывает повторяющиеся записи
Часто это происходит после замены основного запроса через query_posts() или при неверной настройке offset. Если нужен сдвиг выборки, учитывайте пагинацию отдельно, а не просто добавляйте offset без расчёта.
Запись выводится дважды из-за шаблона
Проверьте, не подключён ли один и тот же partial через get_template_part() в двух местах, а также не дублируется ли блок через хук темы.
Дубль появляется только после плагина
Отключите плагин и проверьте, остаётся ли проблема. Если исчезает, ищите его фильтры запросов, виджеты или блоки, которые он добавляет в контент.
Практические советы по безопасности и производительности
Отладку лучше делать на staging-копии или хотя бы с временным логированием, которое потом удаляется. Не оставляйте error_log в боевом коде без необходимости. Для запросов, которые не требуют подсчёта общего числа записей, используйте 'no_found_rows' => true — это уменьшает лишнюю нагрузку на базу.
Если вы работаете с крупным сайтом, полезно держать под рукой инструменты для чистки дублей и технической оптимизации. В некоторых случаях быстрее сначала убрать лишние SEO-дубли и мусорные шаблонные элементы, а уже потом править запросы. Для этого может пригодиться Clearfy Pro: https://wpshop.ru/plugins/clearfy.
Но даже с плагином логика остаётся той же: сначала локализовать источник дубля, потом убрать причину, затем проверить результат на реальных шаблонах и страницах пагинации.