Оглавление

Ведение блога или новостного портала на WordPress требует регулярного контроля за контентом, особенно если на сайте публикуются статьи с обязательными изображениями. Но бывает так, что картинки теряются из-за удаления файлов, сбоя загрузки или проблем с хостингом. В таких случаях на сайте остаются записи без миниатюр, что может испортить внешний вид и негативно сказаться на SEO.

В этой статье разберём, как автоматизировать удаление записей с отсутствующими миниатюрами с помощью WP-CLI.

Что делает скрипт?

Этот PHP-скрипт выполняет следующие задачи:

  1. Сканирует все записи в WordPress, у которых установлена миниатюра.
  2. Проверяет наличие изображений на сервере и доступность их по URL.
  3. Удаляет записи, у которых:
    • Миниатюра отсутствует физически на сервере.
    • Миниатюра недоступна по HTTP (отдаёт 404 или другую ошибку).
    • Миниатюра не задана вообще.
  4. Выводит статистику о количестве обработанных записей, найденных проблемах и количестве удалённых постов.

Исходный код скрипта

Добавим поддержку WP-CLI команды, чтобы можно было вызывать скрипт с помощью wp delete_missing_images.

if ( defined( 'WP_CLI' ) && WP_CLI ) {
    // Регистрация команды
    WP_CLI::add_command( 'delete_missing_images', 'delete_posts_with_missing_featured_image' );
}

function delete_posts_with_missing_featured_image() {
    $posts_per_page = 1000;  // Количество записей для обработки за один запрос
    $page = 1;               // Начальная страница пагинации
    $total_deleted = 0;       // Счётчик удалённых записей
    $total_checked = 0;       // Счётчик проверенных записей
    $total_no_image = 0;      // Счётчик записей без изображения

    $total_posts_count = count( get_posts( array(
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'meta_query'     => array(
            array(
                'key'     => '_thumbnail_id',
                'compare' => 'EXISTS',
            ),
        ),
        'fields' => 'ids',
    ) ) );

    WP_CLI::log( "Общее количество записей с изображениями: $total_posts_count" );

    do {
        $query_args = array(
            'post_type'      => 'post',
            'posts_per_page' => $posts_per_page,
            'paged'          => $page,
            'meta_query'     => array(
                array(
                    'key'     => '_thumbnail_id',
                    'compare' => 'EXISTS',
                ),
            ),
            'fields' => 'ids'
        );

        $post_ids = get_posts( $query_args );
        $total_posts = count( $post_ids );

        if ( $total_posts > 0 ) {
            foreach ( $post_ids as $post_id ) {
                $total_checked++;
                show_progress_bar( $total_checked, $total_deleted, $total_posts_count );

                $thumbnail_id = get_post_thumbnail_id( $post_id );
                $thumbnail_url = wp_get_attachment_url( $thumbnail_id );

                if ( ! empty( $thumbnail_url ) ) {
                    $file_path = get_attached_file( $thumbnail_id );
                    if ( ! file_exists( $file_path ) ) {
                        WP_CLI::log( "Файл отсутствует. Удаляем запись ID: $post_id" );
                        wp_delete_post( $post_id, true );
                        $total_deleted++;
                    } else {
                        $response = wp_remote_get( $thumbnail_url );
                        $status_code = wp_remote_retrieve_response_code( $response );
                        if ( $status_code == 404 || is_wp_error( $response ) ) {
                            WP_CLI::log( "Изображение недоступно (код $status_code). Удаляем запись ID: $post_id" );
                            wp_delete_post( $post_id, true );
                            $total_deleted++;
                        }
                    }
                } else {
                    WP_CLI::log( "Миниатюра отсутствует. Удаляем запись ID: $post_id" );
                    $total_no_image++;
                    wp_delete_post( $post_id, true );
                    $total_deleted++;
                }

                if ( function_exists( 'wp_cache_flush' ) ) {
                    wp_cache_flush();
                }
            }
        }

        $page++;
    } while ( $total_posts > 0 );

    WP_CLI::log( "\nРезультаты сканирования:\n" );
    WP_CLI::log( "Обработано записей: $total_checked" );
    WP_CLI::log( "Без изображений: $total_no_image" );
    WP_CLI::log( "Удалено записей: $total_deleted" );
    WP_CLI::success( "Сканирование завершено." );
}

function show_progress_bar( $current, $deleted, $total ) {
    $percentage = round( ( $current / $total ) * 100 );
    $bar = str_repeat( '=', ( $percentage / 2 ) ) . str_repeat( ' ', 50 - ( $percentage / 2 ) );
    echo "\r[$bar] $percentage% — Просканировано: $current, Удалено: $deleted";
}

Как запустить?

Запуск через WP-CLI

После добавления скрипта в файл (например, delete_missing_images.php), вы можете вызвать его из командной строки следующим образом:

wp delete_missing_images

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

Использование скрипта в functions.php

Если вам необходимо запускать удаление записей без миниатюр при каждом входе в административную панель WordPress, можно добавить следующий код в functions.php вашей активной темы:

add_action('admin_init', 'delete_posts_with_missing_featured_image');

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

Использование скрипта как отдельного файла

Если вы хотите запускать скрипт вручную или через командную строку, создайте отдельный PHP-файл, например delete_missing_images.php, и вставьте в него код функции delete_posts_with_missing_featured_image(). Затем вы можете выполнить его через WP-CLI:

  1. Подключитесь к серверу через SSH.
  2. Перейдите в корневую папку WordPress.
  3. Запустите скрипт командой: wp eval-file delete_missing_images.php

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

add_action('admin_init', 'delete_posts_with_missing_featured_image');

Этот код автоматически вызовет функцию удаления при каждой загрузке панели администратора WordPress.

Автоматизация с помощью Cron

Если вы хотите запускать этот скрипт автоматически, например, раз в день, добавьте его выполнение в crontab:

  1. Откройте crontab для редактирования: crontab -e
  2. Добавьте строку для выполнения скрипта каждый день в 3 часа ночи: 0 3 * * * /usr/bin/wp delete_missing_images --path=/путь/к/wordpress > /dev/null 2>&1
    • Замените /путь/к/wordpress на путь к вашей установке WordPress.
    • > /dev/null 2>&1 скрывает вывод команды, чтобы не засорять логи. Если вы хотите запускать этот скрипт автоматически, например, раз в день, добавьте его выполнение в crontab:
  3. Откройте crontab для редактирования: crontab -e
  4. Добавьте строку для выполнения скрипта каждый день в 3 часа ночи: 0 3 * * * /usr/bin/wp eval-file /путь/к/файлу.php --path=/путь/к/wordpress
    • Замените /путь/к/файлу.php на путь к вашему скрипту.
    • Замените /путь/к/wordpress на путь к вашей установке WordPress.

Этот скрипт предназначен для использования через WP-CLI (интерфейс командной строки WordPress). Для его запуска:

  1. Подключитесь к серверу по SSH.
  2. Перейдите в корневую папку WordPress.
  3. Введите команду: wp eval-file путь_к_файлу.php

Заключение

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