{"id":18743457,"date":"2025-12-04T21:20:29","date_gmt":"2025-12-04T21:20:29","guid":{"rendered":"https:\/\/wordpress.org\/support\/topic\/database-table-size\/"},"modified":"2025-12-04T21:20:29","modified_gmt":"2025-12-04T21:20:29","slug":"database-table-size","status":"publish","type":"topic","link":"https:\/\/wordpress.org\/support\/topic\/database-table-size\/","title":{"rendered":"Database Table Size"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Hi, <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I inherited a wordpress site with huge mailpoet table sizes. I see from comments etc there is no easy way to fix this other than manual deletes.  I&#8217;ve created a script to do clean ups. Would like to <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A) offer it to the community to be used<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">B) get you guys to check if it is safe (ie doesnt delete stuff it shouldn&#8217;t). Its set to 6 months lof logs and 24 months of stats. It assumes Updraft backups but thats easy to change. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php<br \/>\/**<br \/> * MailPoet Database Cleanup Script<br \/> *<br \/> * Cleans up old MailPoet data to reduce database size<br \/> * - Tasks\/Queues\/Logs: 6 months retention<br \/> * - Statistics: 2 years retention<br \/> *<br \/> * Run via server cron<br \/> *<br \/> * Assumes you have Updraft installed <br \/> *   - but can be changed for other backup solutions<br \/> *<br \/> *\/<br \/><br \/>\/\/ Configuration<br \/>\/\/ Set WP_Path to your WordPress folder<br \/>define('WP_PATH', '\/home\/user\/htdocs\/url');<br \/><br \/>\/\/ Set LOG_FILE to your Logs folder<br \/>define('LOG_FILE', '\/home\/user\/logs\/mailpoet-cleanup.log');<br \/><br \/>\/\/ Start logging<br \/>$start_time = microtime(true);<br \/>log_message(\"=== MailPoet Cleanup Started ===\");<br \/><br \/>\/\/ Load WordPress<br \/>if (!file_exists(WP_PATH . '\/wp-load.php')) {<br \/>    log_message(\"ERROR: WordPress not found at \" . WP_PATH, true);<br \/>    exit(1);<br \/>}<br \/><br \/>define('WP_USE_THEMES', false);<br \/>require_once(WP_PATH . '\/wp-load.php');<br \/><br \/>global $wpdb;<br \/><br \/>\/\/ Calculate date thresholds<br \/>$six_months_ago = date('Y-m-d H:i:s', strtotime('-6 months'));<br \/>$two_years_ago = date('Y-m-d H:i:s', strtotime('-24 months'));<br \/><br \/>log_message(\"Date thresholds:\");<br \/>log_message(\"  6 months ago: $six_months_ago\");<br \/>log_message(\"  2 years ago: $two_years_ago\");<br \/><br \/>\/\/ Step 1: Run UpdraftPlus Backup<br \/>log_message(\"\\n--- Step 1: Running UpdraftPlus Backup ---\");<br \/>$backup_result = run_backup();<br \/><br \/>if ($backup_result !== true) {<br \/>    log_message(\"ERROR: Backup failed. Aborting cleanup.\", true);<br \/>    exit(1);<br \/>}<br \/><br \/>log_message(\"Backup completed successfully\");<br \/><br \/>\/\/ Step 2: Clean up scheduled_tasks with cascade<br \/>log_message(\"\\n--- Step 2: Cleaning Scheduled Tasks (6 months) ---\");<br \/>cleanup_scheduled_tasks($wpdb, $six_months_ago);<br \/><br \/>\/\/ Step 3: Clean up logs<br \/>log_message(\"\\n--- Step 3: Cleaning Logs (6 months) ---\");<br \/>cleanup_logs($wpdb, $six_months_ago);<br \/><br \/>\/\/ Step 4: Clean up statistics (2 years)<br \/>log_message(\"\\n--- Step 4: Cleaning Statistics (2 years) ---\");<br \/>cleanup_statistics($wpdb, $two_years_ago);<br \/><br \/>\/\/ Summary<br \/>$execution_time = round(microtime(true) - $start_time, 2);<br \/>log_message(\"\\n=== Cleanup Completed in {$execution_time}s ===\\n\");<br \/><br \/>\/\/ ============================================================================<br \/>\/\/ FUNCTIONS<br \/>\/\/ ============================================================================<br \/><br \/>\/**<br \/> * Run UpdraftPlus backup via WP-CLI<br \/> *\/<br \/>function run_backup() {<br \/>    $wp_dir = WP_PATH;<br \/>    $command = \"cd $wp_dir &amp;&amp; wp updraftplus backup --incremental 2&gt;&amp;1\";<br \/><br \/>    log_message(\"Running: $command\");<br \/>    exec($command, $output, $return_code);<br \/><br \/>    foreach ($output as $line) {<br \/>        log_message(\"  \" . $line);<br \/>    }<br \/><br \/>    if ($return_code !== 0) {<br \/>        log_message(\"Backup command returned error code: $return_code\");<br \/>        return false;<br \/>    }<br \/><br \/>    return true;<br \/>}<br \/><br \/>\/**<br \/> * Clean up scheduled_tasks with cascading deletes<br \/> *\/<br \/>function cleanup_scheduled_tasks($wpdb, $date_threshold) {<br \/>    \/\/ Find old task IDs<br \/>    $old_task_ids = $wpdb-&gt;get_col($wpdb-&gt;prepare(<br \/>        \"SELECT id FROM {$wpdb-&gt;prefix}mailpoet_scheduled_tasks<br \/>         WHERE (created_at &lt; %s OR updated_at &lt; %s)<br \/>         AND status IN ('completed', 'invalid')\",<br \/>        $date_threshold,<br \/>        $date_threshold<br \/>    ));<br \/><br \/>    if (empty($old_task_ids)) {<br \/>        log_message(\"No old scheduled tasks found\");<br \/>        return;<br \/>    }<br \/><br \/>    $task_count = count($old_task_ids);<br \/>    log_message(\"Found $task_count old tasks to delete\");<br \/><br \/>    $task_ids_string = implode(',', array_map('intval', $old_task_ids));<br \/><br \/>    \/\/ Delete child records first (cascade)<br \/><br \/>    \/\/ 1. scheduled_task_subscribers<br \/>    $deleted = $wpdb-&gt;query(<br \/>        \"DELETE FROM {$wpdb-&gt;prefix}mailpoet_scheduled_task_subscribers<br \/>         WHERE task_id IN ($task_ids_string)\"<br \/>    );<br \/>    log_message(\"  Deleted $deleted records from scheduled_task_subscribers\");<br \/><br \/>    \/\/ 2. sending_queues<br \/>    $deleted = $wpdb-&gt;query(<br \/>        \"DELETE FROM {$wpdb-&gt;prefix}mailpoet_sending_queues<br \/>         WHERE task_id IN ($task_ids_string)\"<br \/>    );<br \/>    log_message(\"  Deleted $deleted records from sending_queues\");<br \/><br \/>    \/\/ 3. Finally delete the tasks themselves<br \/>    $deleted = $wpdb-&gt;query(<br \/>        \"DELETE FROM {$wpdb-&gt;prefix}mailpoet_scheduled_tasks<br \/>         WHERE id IN ($task_ids_string)\"<br \/>    );<br \/>    log_message(\"  Deleted $deleted records from scheduled_tasks\");<br \/>}<br \/><br \/>\/**<br \/> * Clean up log tables<br \/> *\/<br \/>function cleanup_logs($wpdb, $date_threshold) {<br \/>    \/\/ mailpoet_log<br \/>    $deleted = $wpdb-&gt;query($wpdb-&gt;prepare(<br \/>        \"DELETE FROM {$wpdb-&gt;prefix}mailpoet_log<br \/>         WHERE created_at &lt; %s\",<br \/>        $date_threshold<br \/>    ));<br \/>    log_message(\"  Deleted $deleted records from mailpoet_log\");<br \/><br \/>    \/\/ automation_run_logs<br \/>    $deleted = $wpdb-&gt;query($wpdb-&gt;prepare(<br \/>        \"DELETE FROM {$wpdb-&gt;prefix}mailpoet_automation_run_logs<br \/>         WHERE started_at &lt; %s OR updated_at &lt; %s\",<br \/>        $date_threshold,<br \/>        $date_threshold<br \/>    ));<br \/>    log_message(\"  Deleted $deleted records from automation_run_logs\");<br \/>}<br \/><br \/>\/**<br \/> * Clean up statistics tables (2 years)<br \/> *\/<br \/>function cleanup_statistics($wpdb, $date_threshold) {<br \/>    $tables = &#091;<br \/>        'mailpoet_statistics_newsletters' =&gt; 'sent_at',<br \/>        'mailpoet_statistics_clicks' =&gt; 'created_at',<br \/>        'mailpoet_statistics_opens' =&gt; 'created_at',<br \/>        'mailpoet_statistics_bounces' =&gt; 'created_at',<br \/>        'mailpoet_statistics_unsubscribes' =&gt; 'created_at',<br \/>        'mailpoet_statistics_forms' =&gt; 'created_at',<br \/>        'mailpoet_statistics_woocommerce_purchases' =&gt; 'created_at',<br \/>    ];<br \/><br \/>    foreach ($tables as $table =&gt; $date_column) {<br \/>        $full_table = $wpdb-&gt;prefix . $table;<br \/><br \/>        \/\/ Check if table exists<br \/>        $table_exists = $wpdb-&gt;get_var(\"SHOW TABLES LIKE '$full_table'\");<br \/>        if (!$table_exists) {<br \/>            log_message(\"  Table $table does not exist, skipping\");<br \/>            continue;<br \/>        }<br \/><br \/>        $deleted = $wpdb-&gt;query($wpdb-&gt;prepare(<br \/>            \"DELETE FROM $full_table WHERE $date_column &lt; %s\",<br \/>            $date_threshold<br \/>        ));<br \/><br \/>        log_message(\"  Deleted $deleted records from $table\");<br \/>    }<br \/>}<br \/><br \/>\/**<br \/> * Log a message to file and stdout<br \/> *\/<br \/>function log_message($message, $error = false) {<br \/>    $timestamp = date('Y-m-d H:i:s');<br \/>    $log_line = \"&#091;$timestamp] $message\\n\";<br \/><br \/>    \/\/ Write to log file<br \/>    $log_dir = dirname(LOG_FILE);<br \/>    if (!is_dir($log_dir)) {<br \/>        mkdir($log_dir, 0755, true);<br \/>    }<br \/>    file_put_contents(LOG_FILE, $log_line, FILE_APPEND);<br \/><br \/>    \/\/ Also output to stdout<br \/>    echo $message . \"\\n\";<br \/><br \/>    if ($error) {<br \/>        error_log($log_line);<br \/>    }<br \/>}<br \/><\/code><\/pre>\n","protected":false},"template":"","class_list":["post-18743457","topic","type-topic","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/topic\/18743457","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/topic"}],"about":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/types\/topic"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/topic\/18743457\/revisions"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/support\/wp-json\/wp\/v2\/media?parent=18743457"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}