diff --git a/bulk-edit-cron-offload.php b/bulk-edit-cron-offload.php index 4aedcab57da06cc71bc9f073b793768d16ade82b..3f1f58df05cd7a072daf7a94e3b54080d7dfa588 100644 --- a/bulk-edit-cron-offload.php +++ b/bulk-edit-cron-offload.php @@ -20,5 +20,6 @@ require __DIR__ . '/includes/utils.php'; // Plugin functionality. require __DIR__ . '/includes/class-main.php'; require __DIR__ . '/includes/class-delete-all.php'; +require __DIR__ . '/includes/class-delete-permanently.php'; require __DIR__ . '/includes/class-move-to-trash.php'; require __DIR__ . '/includes/class-restore-from-trash.php'; diff --git a/includes/class-delete-permanently.php b/includes/class-delete-permanently.php new file mode 100644 index 0000000000000000000000000000000000000000..c56a137208007beaac7ea90e2b6bc81a55f66044 --- /dev/null +++ b/includes/class-delete-permanently.php @@ -0,0 +1,157 @@ +<?php +/** + * Offload "Delete Permanently" + * + * @package Bulk_Edit_Cron_Offload + */ + +namespace Automattic\WP\Bulk_Edit_Cron_Offload; + +/** + * Class Delete_Permanently + */ +class Delete_Permanently { + /** + * Class constants + */ + const ACTION = 'delete'; + + const ADMIN_NOTICE_KEY = 'bulk_edit_cron_offload_delete_permanently'; + + /** + * Register this bulk process' hooks + */ + public static function register_hooks() { + add_action( Main::build_hook( self::ACTION ), array( __CLASS__, 'process' ) ); + add_action( Main::build_cron_hook( self::ACTION ), array( __CLASS__, 'process_via_cron' ) ); + + add_action( 'admin_notices', array( __CLASS__, 'admin_notices' ) ); + add_filter( 'posts_where', array( __CLASS__, 'hide_posts_pending_delete' ), 999, 2 ); + } + + /** + * Handle a request to delete selected posts from the trash + * + * @param object $vars Bulk-request variables. + */ + public static function process( $vars ) { + $action_scheduled = Main::next_scheduled( $vars ); + + if ( empty( $action_scheduled ) ) { + Main::schedule_processing( $vars ); + Main::do_admin_redirect( self::ADMIN_NOTICE_KEY, true ); + } else { + Main::do_admin_redirect( self::ADMIN_NOTICE_KEY, false ); + } + } + + /** + * Cron callback to move requested items to trash + * + * @param object $vars Bulk-request variables. + */ + public static function process_via_cron( $vars ) { + $count = 0; + + if ( is_array( $vars->posts ) && ! empty( $vars->posts ) ) { + require_once ABSPATH . '/wp-admin/includes/post.php'; + + $deleted = array(); + $locked = array(); + $auth_error = array(); + $error = array(); + + foreach ( $vars->posts as $post_id ) { + // Can the user delete this post? + if ( ! user_can( $vars->user_id, 'delete_post', $post_id ) ) { + $auth_error[] = $post_id; + continue; + } + + // Post is locked by someone, so leave it alone. + if ( false !== wp_check_post_lock( $post_id ) ) { + $locked[] = $post_id; + continue; + } + + // Try deleting. + $post_deleted = wp_delete_post( $post_id ); + if ( $post_deleted ) { + $deleted[] = $post_id; + } else { + $error[] = $post_id; + } + + // Take a break periodically. + if ( 0 === $count++ % 50 ) { + stop_the_insanity(); + sleep( 3 ); + } + } + + $results = compact( 'deleted', 'locked', 'auth_error', 'error' ); + do_action( 'bulk_edit_cron_offload_move_to_trash_request_completed', $results, $vars ); + } else { + do_action( 'bulk_edit_cron_offload_move_to_trash_request_no_posts', $vars->posts, $vars ); + } + } + + /** + * Let the user know what's going on + */ + public static function admin_notices() { + $screen = get_current_screen(); + + $type = ''; + $message = ''; + + if ( isset( $_REQUEST[ self::ADMIN_NOTICE_KEY ] ) ) { + if ( 1 === (int) $_REQUEST[ self::ADMIN_NOTICE_KEY ] ) { + $type = 'success'; + $message = __( 'Success! The selected posts will be deleted shortly.', 'bulk-edit-cron-offload' ); + } else { + $type = 'error'; + $message = __( 'The selected posts are already scheduled to be deleted.', 'bulk-edit-cron-offload' ); + } + } elseif ( 'edit' === $screen->base && isset( $_REQUEST['post_status'] ) && 'trash' === $_REQUEST['post_status'] ) { + if ( Main::get_post_ids_for_pending_events( self::ACTION, $screen->post_type, 'trash' ) ) { + $type = 'warning'; + $message = __( 'Some items that would normally be shown here are waiting to be deleted permanently. These items are hidden until then.', 'bulk-edit-cron-offload' ); + } + } + + Main::render_admin_notice( $type, $message ); + } + + /** + * When a delete is pending for a given post type, hide those posts in the admin + * + * @param string $where Posts' WHERE clause. + * @param object $q WP_Query object. + * @return string + */ + public static function hide_posts_pending_delete( $where, $q ) { + if ( ! is_admin() || ! $q->is_main_query() ) { + return $where; + } + + if ( 'edit' !== get_current_screen()->base ) { + return $where; + } + + if ( 'trash' === $q->get( 'post_status' ) ) { + return $where; + } + + $post__not_in = Main::get_post_ids_for_pending_events( self::ACTION, $q->get( 'post_type' ), $q->get( 'post_status' ) ); + + if ( ! empty( $post__not_in ) ) { + $post__not_in = implode( ',', $post__not_in ); + $where .= ' AND ID NOT IN(' . $post__not_in . ')'; + } + + return $where; + } +} + +Delete_Permanently::register_hooks(); diff --git a/includes/class-main.php b/includes/class-main.php index 00b958f26d64ec7b0dcb5739d2ef3ea4849c5507..3d4e3c13224cb99c17d245194effff778ad9f5f6 100644 --- a/includes/class-main.php +++ b/includes/class-main.php @@ -151,7 +151,7 @@ class Main { */ public static function bulk_action_allowed( $action ) { $allowed_actions = array( - 'delete', // TODO: "Delete permantently" in Trash. + 'delete', // class Delete_Permanently. 'delete_all', // class Delete_All. 'edit', 'trash', // class Move_To_trash. @@ -257,7 +257,7 @@ class Main { /** * Find the next scheduled instance of a given action, regardless of arguments * - * @param string $bulk_action Bulk action to filter by. + * @param string $bulk_action Bulk action to filter by. * @param string $post_type Post type hook is scheduled for. * @return array */