2026年11月9日

2026年11月9日

WordPressの不要データを自動的に削除する方法・DB肥大化防止

はじめに

「データベースがどんどん大きくなっている」「ゴミ箱やリビジョンの削除を手動でやるのが面倒」——WordPressの不要データを自動削除する仕組みを設定しておけば、DBの肥大化を防いでパフォーマンスを維持できます。

症状・原因

WordPressは投稿を更新するたびにリビジョンを保存し、削除した投稿はゴミ箱に保管されます。また、プラグインが使うTransient(一時データ)も期限切れ後も残り続けることがあります。これらが長期間蓄積するとwp_posts・wp_optionsテーブルが肥大化します。

解決手順

ステップ1:wp-config.phpで基本的なクリーンアップ設定をする

// wp-config.php: 不要データを制御する定数

// ゴミ箱を自動空にする日数(デフォルト30日)
define( 'EMPTY_TRASH_DAYS', 7 ); // 7日後に自動削除

// ゴミ箱を無効化する(即時削除)
// define( 'EMPTY_TRASH_DAYS', 0 ); // 0=ゴミ箱なし

// 投稿リビジョンの保存数を制限
define( 'WP_POST_REVISIONS', 3 );  // 最新3件のみ保持
// define( 'WP_POST_REVISIONS', false ); // リビジョン無効

// 自動保存の間隔(秒)
define( 'AUTOSAVE_INTERVAL', 300 ); // 5分ごと(デフォルト60秒)

// WordPressのCron(擬似Cron)を無効化して外部Cronを使う場合
// define( 'DISABLE_WP_CRON', true );

ステップ2:WP-Cronで定期クリーンアップを設定する

// functions.php: 定期的なクリーンアップジョブを登録

// カスタムスケジュールを追加(毎日深夜)
add_filter( 'cron_schedules', function( $schedules ) {
    $schedules['daily_midnight'] = [
        'interval' => DAY_IN_SECONDS,
        'display'  => '毎日',
    ];
    return $schedules;
} );

// クリーンアップイベントをスケジュール
add_action( 'wp', function() {
    if ( ! wp_next_scheduled( 'my_cleanup_event' ) ) {
        // 翌日の深夜3時に初回実行
        $midnight = strtotime( 'tomorrow 3:00 AM' );
        wp_schedule_event( $midnight, 'daily', 'my_cleanup_event' );
    }
} );

// クリーンアップ処理
add_action( 'my_cleanup_event', 'my_run_cleanup' );

function my_run_cleanup() {
    global $wpdb;

    // 1. 期限切れTransientを削除
    $now = time();
    $wpdb->query(
        $wpdb->prepare(
            "DELETE FROM $wpdb->options
             WHERE option_name LIKE %s
             AND option_value < %d",
            '_transient_timeout_%',
            $now
        )
    );
    // 対応するTransient本体も削除
    $wpdb->query(
        "DELETE FROM $wpdb->options
         WHERE option_name LIKE '_transient_%'
         AND option_name NOT LIKE '_transient_timeout_%'
         AND REPLACE(option_name, '_transient_', '_transient_timeout_')
             NOT IN (SELECT option_name FROM $wpdb->options)"
    );

    // 2. ゴミ箱の投稿(EMPTY_TRASH_DAYS日を超えたもの)を削除
    $trash_days = defined( 'EMPTY_TRASH_DAYS' ) ? (int) EMPTY_TRASH_DAYS : 30;
    $wpdb->query(
        $wpdb->prepare(
            "DELETE FROM $wpdb->posts
             WHERE post_status = 'trash'
             AND post_modified < %s",
            gmdate( 'Y-m-d H:i:s', time() - $trash_days * DAY_IN_SECONDS )
        )
    );

    // 3. 自動下書き(24時間以上前)を削除
    $wpdb->query(
        "DELETE FROM $wpdb->posts
         WHERE post_status = 'auto-draft'
         AND post_modified < DATE_SUB(NOW(), INTERVAL 1 DAY)"
    );

    // 4. スパムコメントを削除
    $wpdb->query(
        "DELETE FROM $wpdb->comments WHERE comment_approved = 'spam'"
    );

    // 5. 孤立したpostmetaを削除
    $wpdb->query(
        "DELETE pm FROM $wpdb->postmeta pm
         LEFT JOIN $wpdb->posts p ON p.ID = pm.post_id
         WHERE p.ID IS NULL"
    );

    // ログ記録(オプション)
    update_option( 'my_last_cleanup', current_time( 'mysql' ) );
}

ステップ3:投稿保存時にリビジョンを制御する

// 投稿タイプ別にリビジョン数を制御
add_filter( 'wp_revisions_to_keep', function( $num, $post ) {
    // ニュース投稿は3件のみ
    if ( 'news' === $post->post_type ) {
        return 3;
    }
    // 固定ページは5件
    if ( 'page' === $post->post_type ) {
        return 5;
    }
    // その他は2件
    return 2;
}, 10, 2 );

// 既存の古いリビジョンを一括削除(初回設定時)
add_action( 'admin_init', function() {
    if ( ! get_option( 'my_revisions_cleaned' ) ) {
        global $wpdb;

        // 投稿ごとに最新3件以外のリビジョンを削除
        $wpdb->query(
            "DELETE FROM $wpdb->posts
             WHERE post_type = 'revision'
             AND ID NOT IN (
                 SELECT * FROM (
                     SELECT ID FROM $wpdb->posts
                     WHERE post_type = 'revision'
                     ORDER BY post_modified DESC
                     LIMIT 9999
                 ) tmp
             )"
        );

        update_option( 'my_revisions_cleaned', true );
    }
} );

ステップ4:メディアの未使用ファイルを検出する

// functions.php: 未使用のメディアファイルを検出するツール
add_action( 'admin_menu', function() {
    add_management_page(
        '未使用メディア一覧',
        '未使用メディア',
        'manage_options',
        'unused-media',
        'my_unused_media_page'
    );
} );

function my_unused_media_page() {
    global $wpdb;

    // 投稿・メタで参照されていない添付ファイルを検出
    $unused = $wpdb->get_results(
        "SELECT p.ID, p.post_title, p.guid
         FROM $wpdb->posts p
         WHERE p.post_type = 'attachment'
         AND p.ID NOT IN (
             SELECT pm.meta_value FROM $wpdb->postmeta pm
             WHERE pm.meta_key = '_thumbnail_id'
         )
         AND p.ID NOT IN (
             SELECT post_parent FROM $wpdb->posts
             WHERE post_parent > 0 AND post_type != 'attachment'
         )
         LIMIT 50"
    );

    echo '<div class="wrap"><h1>未使用のメディアファイル</h1>';
    echo '<table class="wp-list-table widefat"><thead><tr><th>ID</th><th>タイトル</th><th>URL</th></tr></thead><tbody>';
    foreach ( $unused as $item ) {
        echo '<tr><td>' . esc_html( $item->ID ) . '</td><td>' . esc_html( $item->post_title ) . '</td><td>' . esc_html( $item->guid ) . '</td></tr>';
    }
    echo '</tbody></table></div>';
}

ステップ5:クリーンアップ状況を監視する

# WP-CLIでCronジョブの状態を確認
wp cron event list
wp cron event run my_cleanup_event  # 手動テスト実行

# 前回実行時刻を確認
wp option get my_last_cleanup

# Transientの残存数を確認
wp db query "SELECT COUNT(*) FROM wp_options WHERE option_name LIKE '_transient_%'"

# リビジョンの残存数
wp db query "SELECT COUNT(*) FROM wp_posts WHERE post_type='revision'"

# DBサイズの変化を記録
wp db size

注意事項

  • EMPTY_TRASH_DAYSを0に設定するとゴミ箱が無効化され、削除した投稿は即時完全削除されます。誤削除のリスクが高まるため、通常は7〜14日程度の設定を推奨します。
  • WP-Cronはデフォルトでページが表示されたときに実行されます。トラフィックが少ないサイトでは実行が遅延する場合があります。重要なクリーンアップジョブはサーバーのシステムCronでwp cron event runを呼び出す方が確実です。
  • 孤立したpostmetaの削除は慎重に行ってください。プラグインによってはpost_id=0や存在しない投稿IDにメタデータを意図的に保存する場合があります。

まとめ

不要データの自動削除は「wp-config.phpでEMPTY_TRASH_DAYS・WP_POST_REVISIONS設定→WP-Cronで日次クリーンアップジョブ登録→Transient・ゴミ箱・スパム・孤立postmetaを定期削除→WP-CLIで状況監視」の流れで整備できます。関連記事:WordPressのデータベースを最適化する方法、WordPressのリビジョン数を制限する方法。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲