'shapeoptions_group', 'post_status' => $statuses, 'posts_per_page' => 100, 'fields' => 'ids', 'no_found_rows' => true, ) ); foreach ( $groups as $group_id ) { wp_delete_post( $group_id, true ); } } while ( count( $groups ) === 100 ); shapeoptions_uninstall_remove_uploads(); delete_option( 'shapeoptions_version' ); delete_option( 'shapeoptions_install_time' ); delete_option( 'shapeoptions_style_settings' ); delete_option( 'shapeoptions_delete_data_on_uninstall' ); } /** * Remove the customer uploads that are the plugin's to remove. * * `uploads/shapeoptions/tmp/` holds files that were put in a cart and never * bought — plugin data, and it goes. * * `uploads/shapeoptions/orders/` holds files a real order references, and it * stays. This is the same decision the cleanup above already makes about * `_shapeoptions_options` order-line-item meta: wiping the plugin must not reach into * the order history. Deleting these files while keeping the meta that points * at them would have been the worst of both — orders still listing an * attachment, with nothing behind the link. The Danger zone says plainly that * they are kept and where to find them. * * Once `orders/` is gone or empty, the whole `shapeoptions` folder goes with * it, guard files and all — there is then nothing left to guard. * * Uses WP_Filesystem rather than rmdir()/unlink() so hosts on a non-direct * filesystem transport are handled too. Guarded so it can only ever delete * inside the uploads basedir, and a no-op when the folder was never created * or when no filesystem transport is available (files are then simply left). */ function shapeoptions_uninstall_remove_uploads() { $uploads = wp_get_upload_dir(); if ( empty( $uploads['basedir'] ) || ! empty( $uploads['error'] ) ) { return; } $basedir = wp_normalize_path( trailingslashit( realpath( $uploads['basedir'] ) ?: $uploads['basedir'] ) ); $root = wp_normalize_path( $basedir . 'shapeoptions' ); if ( ! is_dir( $root ) ) { return; } $orders = $root . '/orders'; $keep_orders = is_dir( $orders ) && shapeoptions_uninstall_dir_has_files( $orders ); $target = $keep_orders ? $root . '/tmp' : $root; if ( ! is_dir( $target ) ) { return; } $real = wp_normalize_path( realpath( $target ) ?: '' ); if ( '' === $real || 0 !== strpos( $real . '/', $basedir ) ) { return; } global $wp_filesystem; if ( ! $wp_filesystem ) { require_once ABSPATH . 'wp-admin/includes/file.php'; if ( ! WP_Filesystem() ) { return; } } if ( $wp_filesystem ) { $wp_filesystem->delete( $real, true ); } } /** * Does a directory contain at least one file, at any depth? * * @param string $dir Absolute path. * @return bool */ function shapeoptions_uninstall_dir_has_files( $dir ) { foreach ( (array) glob( trailingslashit( $dir ) . '*' ) as $entry ) { if ( is_file( $entry ) ) { return true; } if ( is_dir( $entry ) && shapeoptions_uninstall_dir_has_files( $entry ) ) { return true; } } return false; } if ( is_multisite() ) { foreach ( get_sites( array( 'fields' => 'ids', 'number' => 0 ) ) as $shapeoptions_blog_id ) { switch_to_blog( $shapeoptions_blog_id ); shapeoptions_uninstall_cleanup(); restore_current_blog(); } unset( $shapeoptions_blog_id ); } else { shapeoptions_uninstall_cleanup(); }