robotstxt-smtp/uninstall.php
2026-08-17 19:16:01 +00:00

236 lines
7.6 KiB
PHP

<?php
/**
* Uninstall routines for the core SMTP plugin.
*
* @package Robotstxt_SMTP
*/
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit;
}
// Check if user wants to delete data on uninstall.
$should_delete_data = false;
if ( function_exists( 'is_multisite' ) && is_multisite() ) {
// Check network option first, fallback to first site option.
$network_options = get_site_option( 'robotstxt_smtp_network_options', array() );
if ( is_array( $network_options ) && ! empty( $network_options['delete_data_on_uninstall'] ) ) {
$should_delete_data = true;
} else {
$sites = get_sites(
array(
'number' => 1,
'fields' => 'ids',
)
);
$first_site_id = ! empty( $sites ) ? $sites[0] : 1;
$site_options = get_blog_option( $first_site_id, 'robotstxt_smtp_options', array() );
$should_delete_data = is_array( $site_options ) && ! empty( $site_options['delete_data_on_uninstall'] );
}
} else {
$options = get_option( 'robotstxt_smtp_options', array() );
$should_delete_data = is_array( $options ) && ! empty( $options['delete_data_on_uninstall'] );
}
// Exit early if user doesn't want to delete data.
if ( ! $should_delete_data ) {
return;
}
if ( ! function_exists( 'robotstxt_smtp_uninstall_cleanup_site' ) ) {
/**
* Removes all plugin data for the current site.
*
* @since 1.1.1
*
* @return void
*/
function robotstxt_smtp_uninstall_cleanup_site(): void {
// Delete core SMTP plugin options.
delete_option( 'robotstxt_smtp_options' );
// Delete Newsletter add-on options.
delete_option( 'robotstxt_smtp_newsletter_options' );
// Delete logs (shared by core and add-ons).
robotstxt_smtp_uninstall_delete_logs();
// Delete core SMTP transients.
robotstxt_smtp_uninstall_delete_transient_prefix( 'robotstxt_smtp_tool_', false );
robotstxt_smtp_uninstall_delete_transient_prefix( 'robotstxt_smtp_test_result_', false );
robotstxt_smtp_uninstall_delete_transient_prefix( 'robotstxt_smtp_rate_limit_', false );
// Delete Amazon SES transients.
robotstxt_smtp_uninstall_delete_transient_prefix( 'robotstxt_smtp_amazonses_quota_', false );
// Clear scheduled cron hooks.
wp_clear_scheduled_hook( 'robotstxt_smtp_cleanup_logs' );
wp_clear_scheduled_hook( 'robotstxt_smtp_cleanup_stats' );
wp_clear_scheduled_hook( 'robotstxt_smtp_amazonses_update_quota' );
}
}
if ( ! function_exists( 'robotstxt_smtp_uninstall_cleanup_network' ) ) {
/**
* Removes network-wide plugin data.
*
* @since 1.1.1
*
* @return void
*/
function robotstxt_smtp_uninstall_cleanup_network(): void {
// Delete core SMTP network options.
delete_site_option( 'robotstxt_smtp_network_options' );
delete_site_option( 'robotstxt_smtp_configuration_scope' );
// Delete core SMTP site transients.
robotstxt_smtp_uninstall_delete_transient_prefix( 'robotstxt_smtp_tool_', true );
robotstxt_smtp_uninstall_delete_transient_prefix( 'robotstxt_smtp_test_result_', true );
robotstxt_smtp_uninstall_delete_transient_prefix( 'robotstxt_smtp_rate_limit_', true );
// Delete Amazon SES site transients.
robotstxt_smtp_uninstall_delete_transient_prefix( 'robotstxt_smtp_amazonses_quota_', true );
// Clear WordPress update cache.
delete_site_transient( 'update_plugins' );
}
}
if ( ! function_exists( 'robotstxt_smtp_uninstall_delete_transient_prefix' ) ) {
/**
* Deletes transients that match a prefix for the current context.
*
* @since 1.1.1
*
* @param string $prefix Transient prefix without the internal storage prefix.
* @param bool $is_network Whether to delete network transients.
*
* @return void
*/
function robotstxt_smtp_uninstall_delete_transient_prefix( string $prefix, bool $is_network ): void {
global $wpdb;
if ( $is_network ) {
$stored_prefix = '_site_transient_' . $prefix;
$timeout_prefix = '_site_transient_timeout_' . $prefix;
$delete_callback = 'delete_site_transient';
$timeout_prefix_length = strlen( '_site_transient_timeout_' );
$stored_prefix_length = strlen( '_site_transient_' );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$matches = $wpdb->get_col(
$wpdb->prepare(
"SELECT meta_key FROM {$wpdb->sitemeta} WHERE meta_key LIKE %s OR meta_key LIKE %s",
$wpdb->esc_like( $stored_prefix ) . '%',
$wpdb->esc_like( $timeout_prefix ) . '%'
)
);
} else {
$stored_prefix = '_transient_' . $prefix;
$timeout_prefix = '_transient_timeout_' . $prefix;
$delete_callback = 'delete_transient';
$timeout_prefix_length = strlen( '_transient_timeout_' );
$stored_prefix_length = strlen( '_transient_' );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$matches = $wpdb->get_col(
$wpdb->prepare(
"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
$wpdb->esc_like( $stored_prefix ) . '%',
$wpdb->esc_like( $timeout_prefix ) . '%'
)
);
}
if ( empty( $matches ) ) {
return;
}
foreach ( $matches as $option_name ) {
if ( ! is_string( $option_name ) ) {
continue;
}
if ( str_starts_with( $option_name, $is_network ? '_site_transient_timeout_' : '_transient_timeout_' ) ) {
$transient_key = substr( $option_name, $timeout_prefix_length );
} else {
$transient_key = substr( $option_name, $stored_prefix_length );
}
if ( '' === $transient_key ) {
continue;
}
call_user_func( $delete_callback, $transient_key );
}
}
}
if ( ! function_exists( 'robotstxt_smtp_uninstall_delete_logs' ) ) {
/**
* Deletes all stored SMTP logs for the current site.
*
* @since 1.1.1
*
* @return void
*/
function robotstxt_smtp_uninstall_delete_logs(): void {
do {
$logs = get_posts(
array(
'post_type' => 'robotstxt_smtp_log',
'post_status' => 'any',
'fields' => 'ids',
'posts_per_page' => 100,
'orderby' => 'ID',
'order' => 'ASC',
)
);
foreach ( $logs as $log_id ) {
wp_delete_post( (int) $log_id, true );
}
} while ( ! empty( $logs ) );
}
}
if ( ! function_exists( 'robotstxt_smtp_uninstall_delete_statistics_table' ) ) {
/**
* Drops the statistics table from the database.
*
* @since 2.0.1
*
* @return void
*/
function robotstxt_smtp_uninstall_delete_statistics_table(): void {
global $wpdb;
$table_name = $wpdb->base_prefix . 'robotstxt_smtp_stats';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- DROP TABLE cannot use placeholders; table name is a hardcoded constant prefixed by $wpdb->base_prefix.
$wpdb->query( "DROP TABLE IF EXISTS {$table_name}" );
// Delete the database version option.
delete_site_option( 'robotstxt_smtp_stats_db_version' );
}
}
// Clean up network-wide data.
robotstxt_smtp_uninstall_cleanup_network();
// Clean up site-specific data.
if ( function_exists( 'is_multisite' ) && is_multisite() ) {
$robotstxt_smtp_sites = get_sites( array( 'fields' => 'ids' ) );
foreach ( $robotstxt_smtp_sites as $robotstxt_smtp_site_id ) {
switch_to_blog( (int) $robotstxt_smtp_site_id );
robotstxt_smtp_uninstall_cleanup_site();
restore_current_blog();
}
} else {
robotstxt_smtp_uninstall_cleanup_site();
}
// Drop the statistics table (global, only once).
robotstxt_smtp_uninstall_delete_statistics_table();
// Delete the per-user manager notice dismissal preference (global, only once).
delete_metadata( 'user', 0, 'robotstxt_smtp_manager_notice_dismissed', '', true );