Как найти и убрать дублирующиеся записи в WordPress без плагинов

Дубли в WordPress обычно появляются не из-за одной ошибки, а из-за набора мелких причин: импорт контента, повторная публикация, кривые редиректы, одинаковые slug, архивы с разными URL и копии записей после миграции. На живом сайте это быстро превращается в лишние страницы в индексе, путаницу в админке и проблемы с внутренней перелинковкой.

Если задача не в том, чтобы «почистить всё подряд», а в том, чтобы найти именно дубли и убрать их без лишнего риска, лучше идти по схеме: сначала диагностировать источник, потом выбрать способ удаления, затем проверить, что старые URL действительно исчезли из обхода и не ломают сайт.

Как понять, что у вас именно дубли, а не похожий контент

Сначала стоит отделить настоящие дубли от просто похожих материалов. В WordPress это разные случаи:

  • одинаковый заголовок и почти одинаковый текст у двух записей;
  • одинаковый post_name у старой и новой версии материала;
  • копии страниц после импорта или переноса сайта;
  • архивы автора, рубрик, тегов и пагинации, которые повторяют основной контент;
  • дубли в базе, когда одна и та же запись была создана повторно, а не обновлена.

Если в индексе поисковика есть несколько URL с одним смыслом, это уже не косметическая проблема. Поисковый робот тратит обход на лишние страницы, а сайт сам себе конкурирует в выдаче.

Быстрая диагностика в админке и базе

Для начала проверьте список записей и страниц по одинаковым заголовкам. Это самый простой признак, но он не всегда точный: заголовки могут совпадать, а контент — отличаться. Более надежно смотреть на slug и даты публикации.

Если есть доступ к базе, можно быстро найти одинаковые slug для записей:

SELECT post_name, COUNT(*) AS cnt
FROM wp_posts
WHERE post_type IN ('post', 'page')
  AND post_status NOT IN ('trash', 'auto-draft')
GROUP BY post_name
HAVING cnt > 1;

Этот запрос не покажет все дубли контента, но хорошо ловит повторяющиеся URL-имена. Если у вас нестандартный префикс таблиц, замените wp_ на свой.

Еще один полезный признак — одинаковый post_title у нескольких опубликованных записей:

SELECT post_title, COUNT(*) AS cnt
FROM wp_posts
WHERE post_type = 'post'
  AND post_status = 'publish'
GROUP BY post_title
HAVING cnt > 1;

Это уже не доказательство дубля, но хороший список для ручной проверки.

Что делать: сравнение подходов

Убирать дубли можно тремя способами. У каждого есть компромисс.

ПодходКогда подходитПлюсыМинусы
Ручное удаление в админке1–10 дублейБезопасно, не требует кодаДолго, неудобно при массовой чистке
Скрипт через functions.php или mu-pluginНужно удалить много повторов по правилуМожно автоматизировать и логироватьНужна аккуратность и бэкап
Плагин для очистки дублейЕсли нужен разовый аудит без разработкиБыстрее для редактораЛишняя зависимость, не всегда прозрачно, что именно удаляется

Если задача разовая и у вас есть доступ к коду, практичнее сделать точечный скрипт. Если контентом управляет редакция и проблема повторяется, лучше сначала исправить процесс: импорт, шаблоны, автосохранение, публикацию по расписанию.

Пошаговое решение без плагинов

Ниже — безопасный сценарий для случая, когда нужно найти записи с одинаковым slug и удалить лишние копии, оставив одну актуальную версию. Перед запуском сделайте резервную копию базы.

Шаг 1. Сначала пометить дубли, а не удалять их сразу

Лучше не удалять записи молча. Сначала переведите лишние копии в черновик или корзину, чтобы можно было откатиться. Для этого удобнее использовать небольшой код в mu-plugin или временно в functions.php.

<?php
add_action('admin_init', function () {
    if ( ! current_user_can('manage_options') ) {
        return;
    }

    if ( ! isset($_GET['find_duplicate_posts']) ) {
        return;
    }

    global $wpdb;

    $duplicates = $wpdb->get_results(
        "SELECT post_name, COUNT(*) AS cnt
         FROM {$wpdb->posts}
         WHERE post_type = 'post'
           AND post_status = 'publish'
         GROUP BY post_name
         HAVING cnt > 1"
    );

    echo '<pre>';
    foreach ( $duplicates as $row ) {
        echo esc_html($row->post_name . ' — ' . $row->cnt) . "\n";
    }
    echo '</pre>';
    exit;
});

После добавления кода откройте /wp-admin/?find_duplicate_posts=1 под администратором. Вы получите список slug, которые повторяются. Это не удаление, а аудит.

Шаг 2. Удалить лишние копии по понятному правилу

Если дубль определяется по slug, можно оставить самую свежую запись, а остальные отправить в корзину. Ниже пример, который работает только для записей и только для опубликованных материалов с одинаковым slug.

<?php
add_action('admin_init', function () {
    if ( ! current_user_can('manage_options') ) {
        return;
    }

    if ( ! isset($_GET['cleanup_duplicate_posts']) ) {
        return;
    }

    global $wpdb;

    $rows = $wpdb->get_results(
        "SELECT post_name
         FROM {$wpdb->posts}
         WHERE post_type = 'post'
           AND post_status = 'publish'
         GROUP BY post_name
         HAVING COUNT(*) > 1"
    );

    foreach ( $rows as $row ) {
        $posts = get_posts([
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'name'           => $row->post_name,
            'numberposts'    => -1,
            'orderby'        => 'date',
            'order'          => 'DESC',
            'fields'         => 'ids',
        ]);

        if ( count($posts) <= 1 ) {
            continue;
        }

        // Оставляем самую свежую запись, остальные отправляем в корзину.
        array_shift($posts);

        foreach ( $posts as $post_id ) {
            wp_trash_post($post_id);
        }
    }

    wp_die('Дубли отправлены в корзину. Проверьте список записей вручную.');
});

Запускать такой код нужно один раз и только после бэкапа. После выполнения удалите его, чтобы не оставить в админке рабочую «кнопку» для случайного запуска.

Шаг 3. Если дубли появились после импорта

После миграции часто дублируются не только записи, но и медиа, категории, теги. В этом случае чистить нужно не только wp_posts, но и сопутствующие связи. Если просто удалить записи, а термины и вложения оставить, мусор останется в базе и в медиатеке.

Практически это выглядит так:

  • сначала сверить количество записей до и после импорта;
  • проверить, не создались ли дубли страниц «О нас», «Контакты», «Политика»;
  • просмотреть медиатеку на повторяющиеся файлы с одинаковым названием;
  • убедиться, что старые URL не остались в sitemap и внутренних ссылках.

Проверка результата после очистки

Удалить дубли недостаточно. Нужно проверить, что сайт не продолжает отдавать старые адреса и что поисковик не видит две версии одной страницы.

Что проверить в первую очередь

  • открывается ли основной URL записи без цепочки редиректов;
  • нет ли в админке второго материала с тем же slug;
  • исчезли ли удаленные записи из sitemap;
  • не ведут ли внутренние ссылки на корзину или 404;
  • не осталось ли старых URL в кэше страницы и CDN;
  • не создается ли дубль снова при повторной публикации или импорте.

Если у вас включен кэш, очистите его после удаления дублей. Иначе можно увидеть старую версию страницы даже после того, как запись уже удалена.

Для быстрой проверки ответа сервера используйте curl:

curl -I https://example.com/staryj-url/

Если URL удален правильно, вы должны увидеть либо 301 на актуальную страницу, либо 410 Gone, если адрес намеренно убран без замены. Для дублей это важный момент: поисковику нужно явно показать, что старый адрес больше не является каноническим.

Частые ошибки и как их исправить

Удаляют не дубль, а нужную версию записи

Это случается, когда ориентируются только на заголовок. Один и тот же title может быть у разных материалов. Перед удалением сравните slug, дату, автора, содержимое и входящие ссылки.

Оставляют старый URL без редиректа

Если удалить запись и не настроить редирект, внутренние ссылки и внешние переходы начнут вести на 404. Для страниц, которые уже были в индексе, это плохой сценарий. Если у дублирующейся записи есть замена, лучше сделать 301 на актуальный адрес.

Чистят только записи, но не архивы и таксономии

Иногда дубли создаются не в записях, а в архивных страницах: авторы, теги, рубрики, пагинация. Если проблема именно в индексации, удаление одной записи ничего не изменит. Тогда нужно отдельно проверить robots, sitemap и канонические URL.

Запускают код без бэкапа

Любой массовый скрипт в WordPress должен идти после резервной копии базы и файлов. Это не формальность: если логика отбора дублей ошибочна, откат будет только через бэкап.

Оставляют временный код в продакшене

Код для поиска и удаления дублей не должен висеть в functions.php постоянно. Лучше вынести его в временный mu-plugin, выполнить задачу и удалить файл. Так вы не оставите случайный административный триггер на сайте.

Что можно улучшить после чистки

Если дубли появляются регулярно, проблема обычно не в контенте как таковом, а в процессе. Проверьте:

  • не создаются ли записи повторно через импорт из CSV или XML;
  • не дублирует ли редактор материал вручную вместо обновления;
  • не генерируются ли одинаковые URL из-за шаблона slug;
  • не плодятся ли архивы и служебные страницы, которые лучше закрыть от индексации;
  • не мешает ли кэш показывать старые версии после удаления.

Если нужна не разовая чистка, а системное удаление дублей, удобно сочетать аудит контента с настройкой SEO-правил и очисткой служебных страниц. В таких задачах часто помогает связка из ручной проверки и инструментов для удаления дублей, например Clearfy Pro, если вам нужен именно набор SEO- и cleanup-настроек без написания собственного кода.

Главное правило простое: сначала найти источник дубля, потом удалить лишнее, потом проверить, что старый URL больше не участвует в обходе и не возвращается из кэша.

Как использовать REST API WordPress для создания приложений
30.11.2025
Как отключить WooCommerce Blocks Cart Fragments и убрать лишние запросы
13.08.2026
Как создать плагин для автоматического очищения кеша WordPress
25.11.2025
Как разрешить доступ к файлам WordPress через .htaccess для конкретных IP
17.04.2026
Как отключить AJAX cart fragments в WooCommerce без потери функциональности
10.08.2026