From 814c7682b3afcabb3875b64afc9224f5dc00773e Mon Sep 17 00:00:00 2001 From: yoav-cloud Date: Fri, 24 Apr 2026 19:57:28 +0300 Subject: [PATCH] Proper Uninstall Refactor Deactivation class to utilize Cleanup class for data cleanup and remove redundant methods. Update constant reference for cleaning key. --- php/class-cleanup.php | 251 +++++++++++++++++++++++++++++++++++++ php/class-deactivation.php | 189 +--------------------------- uninstall.php | 24 ++++ 3 files changed, 278 insertions(+), 186 deletions(-) create mode 100644 php/class-cleanup.php create mode 100644 uninstall.php diff --git a/php/class-cleanup.php b/php/class-cleanup.php new file mode 100644 index 000000000..3ea529a89 --- /dev/null +++ b/php/class-cleanup.php @@ -0,0 +1,251 @@ +plugin = $plugin; + + if ( null !== $settings ) { + $this->settings = $settings; + } elseif ( $plugin instanceof Plugin && $plugin->settings instanceof Settings ) { + $this->settings = $plugin->settings; + } + } + + /** + * Run the full cleanup routine. + * + * @param Plugin|null $plugin Plugin instance. + * @param Settings|null $settings Settings instance. + */ + public static function run( Plugin $plugin = null, Settings $settings = null ) { + $cleanup = new self( $plugin, $settings ); + $cleanup->cleanup_user_data(); + $cleanup->cleanup_post_meta(); + $cleanup->cleanup_term_meta(); + $cleanup->cleanup_post_type(); + $cleanup->drop_tables(); + $cleanup->cleanup_options(); + $cleanup->cleanup_cron(); + $cleanup->cleanup_legacy_cron(); + } + + /** + * Cleanup Cloudinary's user data related. + */ + protected function cleanup_user_data() { + $user_meta_keys = array( + '_cld_ui_state', + ); + + foreach ( $user_meta_keys as $key ) { + // Inspired on https://developer.wordpress.org/reference/functions/delete_post_meta_by_key/. + delete_metadata( 'user', null, $key, '', true ); + } + } + + /** + * Cleanup Cloudinary's post meta related. + */ + protected function cleanup_post_meta() { + $post_meta_keys = array_merge( + Sync::META_KEYS, + array( + Global_Transformations::META_FEATURED_IMAGE_KEY, + Global_Transformations::META_ORDER_KEY . '_terms', + Delivery::META_CACHE_KEY, + ) + ); + + foreach ( $post_meta_keys as $key ) { + delete_post_meta_by_key( $key ); + } + } + + /** + * Cleanup Cloudinary's term meta related. + */ + protected function cleanup_term_meta() { + $term_meta_keys = array( + 'cloudinary_transformations_image_freeform', + 'cloudinary_transformations_video_freeform', + ); + + foreach ( $term_meta_keys as $key ) { + // Inspired on https://developer.wordpress.org/reference/functions/delete_post_meta_by_key/. + delete_metadata( 'term', null, $key, '', true ); + } + } + + /** + * Cleanup Cloudinary's post types related. + */ + protected function cleanup_post_type() { + global $wpdb; + + $post_types = array( + Assets::POST_TYPE_SLUG, + ); + + foreach ( $post_types as $type ) { + $wpdb->delete( //phpcs:ignore WordPress.DB.DirectDatabaseQuery + $wpdb->posts, + array( 'post_type' => $type ), + array( '%s' ) + ); + } + } + + /** + * Drop Cloudinary's tables. + */ + protected function drop_tables() { + global $wpdb; + + $tables = array( + Utils::get_relationship_table(), + ); + + foreach ( $tables as $table ) { + $wpdb->query( "DROP TABLE IF EXISTS {$table};" ); // phpcs:ignore WordPress.DB + } + } + + /** + * Cleanup Cloudinary's options related. + */ + protected function cleanup_options() { + if ( $this->settings instanceof Settings ) { + $all = $this->settings->get_param( 'settings' ); + if ( is_array( $all ) ) { + foreach ( $all as $slug => $setting ) { + $this->settings->delete( $slug ); + } + } + } + + if ( $this->plugin instanceof Plugin ) { + $sync = $this->plugin->get_component( 'sync' ); + if ( $sync instanceof Sync && ! empty( $sync->managers['queue'] ) ) { + $queue = $sync->managers['queue']; + $all_threads = $queue->get_threads( 'all' ); + foreach ( $all_threads as $threads ) { + foreach ( $threads as $thread ) { + $queue->reset_thread_queue( $thread ); + delete_post_meta_by_key( $thread ); + } + } + } + } + + $storage_keys = array(); + if ( $this->settings instanceof Settings ) { + $storage_keys = (array) $this->settings->get_storage_keys(); + } + + $option_keys = array_merge( + $storage_keys, + array( + 'cloudinary_setup', + 'cloudinary_main_cache_page', + '_cld_disable_http_upload', + Report::REPORT_KEY, + Media::GLOBAL_VIDEO_TRANSFORMATIONS, + self::CLEANING_KEY, + ) + ); + + $option_keys = array_unique( array_filter( $option_keys ) ); + foreach ( $option_keys as $key ) { + delete_option( $key ); + delete_transient( $key ); + } + } + + /** + * Remove all cron-related tasks. + * + * @return void + */ + protected function cleanup_cron() { + // Get the Cron instance. + $cron_instance = Cron::get_instance(); + $schedule = $cron_instance->get_schedule(); + + // Unregister all registered schedules. + if ( ! empty( $schedule ) ) { + foreach ( array_keys( $schedule ) as $schedule_name ) { + $cron_instance->unregister_schedule( $schedule_name ); + } + } + + // Remove any lock files or objects used by the Locker instance. + $cron_instance->cleanup_locker(); + + // Delete the cron schedule option saved in database. + delete_option( Cron::CRON_META_KEY ); + } + + /** + * Cleanup legacy cron jobs. + * + * @return void + */ + protected function cleanup_legacy_cron() { + wp_clear_scheduled_hook( 'cloudinary_status' ); + + $jobs = array( + 'cloudinary_cleanup_event', + 'cloudinary_rest_api_connectivity', + 'cloudinary_resume_queue', + 'cloudinary_resume_upgrade', + 'cloudinary_sync_items', + ); + + foreach ( $jobs as $job ) { + $time = wp_next_scheduled( $job ); + if ( false !== $time ) { + wp_clear_scheduled_hook( $job ); + } + } + } +} diff --git a/php/class-deactivation.php b/php/class-deactivation.php index 28075e12f..312c1ec1e 100644 --- a/php/class-deactivation.php +++ b/php/class-deactivation.php @@ -7,8 +7,6 @@ namespace Cloudinary; -use Cloudinary\Media\Global_Transformations; -use Cloudinary\Sync\Storage; use WP_Error; use WP_HTTP_Response; use WP_REST_Request; @@ -46,13 +44,6 @@ class Deactivation { */ protected $settings; - /** - * Cleaning data key. - * - * @var string - */ - const CLEANING_KEY = 'cloudinary_cleaning_up'; - /** * Initiate the plugin deactivation. * @@ -459,7 +450,7 @@ public function tag_deactivate( $actions ) { $actions['deactivate'] = str_replace( 'cleanup_user_data(); - $this->cleanup_post_meta(); - $this->cleanup_term_meta(); - $this->cleanup_post_type(); - $this->drop_tables(); - $this->cleanup_options(); - $this->cleanup_cron(); - $this->cleanup_legacy_cron(); - - // If we got this far, let's remove the cron event. + add_option( Cleanup::CLEANING_KEY, true, '', false ); + Cleanup::run( $this->plugin, $this->settings ); wp_clear_scheduled_hook( 'cloudinary_cleanup_event' ); } - - /** - * Cleanup Cloudinary's user data related. - */ - protected function cleanup_user_data() { - $user_meta_keys = array( - '_cld_ui_state', - ); - - foreach ( $user_meta_keys as $key ) { - // Inspired on https://developer.wordpress.org/reference/functions/delete_post_meta_by_key/. - delete_metadata( 'user', null, $key, '', true ); - } - } - - /** - * Cleanup Cloudinary's post meta related. - */ - protected function cleanup_post_meta() { - $post_meta_keys = array_merge( - Sync::META_KEYS, - array( - Global_Transformations::META_FEATURED_IMAGE_KEY, - Global_Transformations::META_ORDER_KEY . '_terms', - Delivery::META_CACHE_KEY, - ) - ); - - foreach ( $post_meta_keys as $key ) { - delete_post_meta_by_key( $key ); - } - } - - /** - * Cleanup Cloudinary's term meta related. - */ - protected function cleanup_term_meta() { - $term_meta_keys = array( - 'cloudinary_transformations_image_freeform', - 'cloudinary_transformations_video_freeform', - ); - - foreach ( $term_meta_keys as $key ) { - // Inspired on https://developer.wordpress.org/reference/functions/delete_post_meta_by_key/. - delete_metadata( 'term', null, $key, '', true ); - } - } - - /** - * Drop Cloudinary's tables. - */ - protected function drop_tables() { - global $wpdb; - - $tables = array( - Utils::get_relationship_table(), - ); - - foreach ( $tables as $table ) { - $wpdb->query( "DROP TABLE IF EXISTS {$table};" ); // phpcs:ignore WordPress.DB - } - } - - /** - * Cleanup Cloudinary's post types related. - */ - protected function cleanup_post_type() { - global $wpdb; - - $post_types = array( - Assets::POST_TYPE_SLUG, - ); - - foreach ( $post_types as $type ) { - $wpdb->delete( //phpcs:ignore WordPress.DB.DirectDatabaseQuery - $wpdb->posts, - array( 'post_type' => $type ), - array( '%s' ) - ); - } - } - - /** - * Cleanup Cloudinary's options related. - */ - protected function cleanup_options() { - $all = $this->settings->get_param( 'settings' ); - foreach ( $all as $slug => $setting ) { - $this->settings->delete( $slug ); - } - - $queue = $this->plugin->get_component( 'sync' )->managers['queue']; - $all_threads = $queue->get_threads( 'all' ); - foreach ( $all_threads as $threads ) { - foreach ( $threads as $thread ) { - $queue->reset_thread_queue( $thread ); - delete_post_meta_by_key( $thread ); - } - } - - $option_keys = array_merge( - $this->settings->get_storage_keys(), - array( - 'cloudinary_setup', - 'cloudinary_main_cache_page', - '_cld_disable_http_upload', - Report::REPORT_KEY, - Media::GLOBAL_VIDEO_TRANSFORMATIONS, - self::CLEANING_KEY, - ) - ); - - foreach ( $option_keys as $key ) { - delete_option( $key ); - delete_transient( $key ); - } - } - - /** - * Remove all cron-related tasks. - * - * @return void - */ - protected function cleanup_cron() { - // Get the Cron instance. - $cron_instance = Cron::get_instance(); - $schedule = $cron_instance->get_schedule(); - - // Unregister all registered schedules. - if ( ! empty( $schedule ) ) { - foreach ( array_keys( $schedule ) as $schedule_name ) { - $cron_instance->unregister_schedule( $schedule_name ); - } - } - - // Remove any lock files or objects used by the Locker instance. - $cron_instance->cleanup_locker(); - - // Delete the cron schedule option saved in database. - delete_option( Cron::CRON_META_KEY ); - } - - /** - * Cleanup legacy cron jobs. - * - * @return void - */ - protected function cleanup_legacy_cron() { - wp_clear_scheduled_hook( 'cloudinary_status' ); - - $jobs = array( - 'cloudinary_rest_api_connectivity', - 'cloudinary_resume_queue', - 'cloudinary_resume_upgrade', - 'cloudinary_sync_items', - ); - - foreach ( $jobs as $job ) { - $time = wp_next_scheduled( $job ); - if ( false !== $time ) { - wp_clear_scheduled_hook( $job ); - } - } - } } diff --git a/uninstall.php b/uninstall.php new file mode 100644 index 000000000..4339925b5 --- /dev/null +++ b/uninstall.php @@ -0,0 +1,24 @@ +init(); +$plugin->plugins_loaded(); +$plugin->setup_settings(); + +\Cloudinary\Cleanup::run( $plugin );