Удаление постов и пользователей wordpress, вместе с соответствующей meta информацией и комментариями — MySQL

от 2019 - 07 - 15

Решал задачу по очистке сайта на wordpress от спама. Там были сотни левых юзеров и ещё больше рекламных постов от них, а так же всевозможных комментариев, больше тысячи. Хотелось всё это дело как-то быстро в три приёма удалить с сайта. Решил сделать напрямую запросы удаления к базе. При этом надо было сохранить настоящих пользователей (человек 7) и их посты, а все лишние, вместе с терминами таксономии и мета информацией — очистить, стереть, удалить.

  1. Получил id всех пользователей для удаления
    Это было довольно просто:

    SELECT id FROM G1vS0wF_users WHERE id NOT IN (1,7,43,49,209,212,214)
    

    Итоговую выгрузку из таблицы, список id’шников я сохранил себе, на всякий, в отдельный файл. Это показано на скрин-шоте:

    Скриншот heidiSQL, базы MySQL wordpress, и запроса

  2. Далее, я обратился к структуре базы данных wordpress в поисках связей между таблицами. Оказалось существует интересующее меня изображение по связям прямо в кодексе:
    https://codex.wordpress.org/Database_Description

    Структура базы данных wordpress

    Структура базы данных wordpress

    Из данной структуры можно понять, что таблица пользователей wp_users связана через поле ID, с тремя пользовательскими таблицами:
    1. wp_posts (внутри которой для связи с таблицей пользователей используется поле post_author, содержащее ID пользователя)
    2. wp_usermeta (дополнительная информация по пользователям, фактически любые мета данные, связана через user_id)
    3. wp_comments (так же через поле user_id)

  3. Теперь у нас есть понимание, из каких таблиц удалять связанные данные, только надо помнить, что с этими таблицами, связаны ещё несколько таблиц, вот список:

    1. С таблицей wp_posts связаны дополнительные таблицы с мета данными и терминами таксономии, из них так же предстоит удалить все строки, которые связаны с удаляемыми постами.

    А именно, таблицы: wp_postmeta, wp_term_relationships, wp_term_taxonomy, wp_terms, wp_termmeta (их также надо чистить, конечно, конкретные запросы читай ниже).

    2. С таблицей wp_comments связана таблица wp_commentmeta.

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

    # Для начала узнаем id всех постов, которые собираемся удалять:
    SELECT ID FROM G1vS0wF_posts WHERE post_author IN (
       # тут вложенный запрос ID'шников пользователей что будут удалены. Пример выше.
       SELECT ID
       FROM G1vS0wF_users 
       WHERE ID NOT IN (1,7,43,49,209,212,214)
    )
    

    Разумеется в данном запросе можно поменять SELECT на DELETE, в тот момент, когда будете уверены, что все связанные данные очищены, и можно удалять сами посты.

  5. Следом уже можно почистить таблицу wp_postmeta, она не имеет дальнейших связей. Конечная. Удаляя из неё строки мы не повредим никаких других связанных таблиц.

    DELETE FROM G1vS0wF_postmeta WHERE post_id IN (
    
       SELECT ID FROM G1vS0wF_posts WHERE post_author IN (
          SELECT ID
          FROM G1vS0wF_users 
          WHERE ID NOT IN (1,7,43,49,209,212,214)
       )
    
    )
    

    Не выполняйте данный запрос бездумно, учтите, что в нём список ID сохраняемых пользователей и постов из моего случая (1,7,43,49,209,212,214), у вас будет другой.

  6. Теперь более сложное — надо очистить от лишних данных таблицы терминов таксономии wp_term_relationships, wp_term_taxonomy, wp_terms, wp_termmeta.
    wp_term_relationships связана с wp_posts через поле object_id, которое указывает на ID записи в таблице wp_posts.
    Однако мы не можем взять и сразу удалить из неё все лишние данные, как в пункте 5, ибо останутся тогда на веки вечные лишние строки в wp_term_taxonomy, wp_terms, wp_termmeta.

    Сложность в том, что один и тот же термин таксономии может принадлежать к разным постам. Некоторые из них мы собираемся удалять, а другие хотим оставить. В связи с этим нельзя без дополнительной проверки удалять все подряд таксономии и их термины. Какое-то быстрое решение этой ситуации мне сейчас быстро придумать не хватит времени, так что вопрос оставлю пока открытым, а данные таблицы не очищенными. Позже, если вспомню, добавлю сюда решение.

    В принципе можно удалить все связи из таблицы wp_term_relationships лишние связи по object_id удаляемых постов.

    DELETE FROM G1vS0wF_term_relationships WHERE object_id IN (
    
       SELECT ID FROM G1vS0wF_posts WHERE post_author IN (
          SELECT ID
          FROM G1vS0wF_users 
          WHERE ID NOT IN (1,7,43,49,209,212,214)
       )
    
    )
    

    А потом воспользоваться решением из данной моей статьи:
    Очистка таблицы MySQL от записей отсутствующих в связанной таблице
    Удаляя все термины wp_terms, wp_termmeta и мета информацию терминов такие, которые отсутствуют теперь в таблице wp_term_relationships.

  7. Настал черёд удаления комментариев. Помним, что с таблицей комментариев связана таблица метаданных и сначала надо чистить её, узнав все ID комментов для удаления.
    Это делается так:

    # Запрос на удаление связанных с комментариями данных из wp_commentmeta
    DELETE FROM G1vS0wF_commentmeta WHERE comment_id IN (
       SELECT comment_ID FROM G1vS0wF_comments WHERE user_id IN (
          SELECT ID
          FROM G1vS0wF_users 
          WHERE ID NOT IN (1,7,43,49,209,212,214)
       )
    );
    
    # Запрос на удаление самих комментариев из wp_comments 
    DELETE FROM G1vS0wF_comments WHERE user_id IN (
       SELECT ID
       FROM G1vS0wF_users 
       WHERE ID NOT IN (1,7,43,49,209,212,214)
    );
    
  8. Сейчас осталось уже совсем простое. Мы наконец удалим все лишние посты, а затем и самих не желательных пользователей:

    # Удаляем все лишние посты
    DELETE FROM G1vS0wF_posts WHERE post_author IN (
       SELECT ID
       FROM G1vS0wF_users 
       WHERE ID NOT IN (1,7,43,49,209,212,214)
    );
    
    # Чистим связанную с пользователями информацию из 
    DELETE FROM G1vS0wF_usermeta WHERE user_id IN (
       SELECT ID
       FROM G1vS0wF_users 
       WHERE ID NOT IN (1,7,43,49,209,212,214)
    );
     
    # Ну а за ней уже и пользователей
    DELETE FROM G1vS0wF_users WHERE ID NOT IN (1,7,43,49,209,212,214);
    

Готово, wordpress очищен.
Далее обсудим

Как предотвратить появление спама на сайте wordpress