Newer
Older
/**
* Offload "Move to Trash"
*
* @package Bulk_Edit_Cron_Offload
*/
namespace Automattic\WP\Bulk_Edit_Cron_Offload;
class Move_To_Trash {
/**
* Class constants
*/
const ADMIN_NOTICE_KEY = 'bulk_edit_cron_offload_move_to_trash';
/**
* Register this bulk process' hooks
*/
public static function register_hooks() {
add_action( Main::build_hook( 'trash' ), array( __CLASS__, 'process' ) );
add_action( Main::build_cron_hook( 'trash' ), array( __CLASS__, 'process_via_cron' ) );
add_action( 'admin_notices', array( __CLASS__, 'admin_notices' ) );
add_filter( 'posts_where', array( __CLASS__, 'hide_posts_pending_move' ), 999, 2 );
* Handle a request to move some posts to the trash
*/
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 );
}
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
}
/**
* 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';
$trashed = array();
$locked = array();
$auth_error = array();
$error = array();
foreach ( $vars->posts as $post_id ) {
// Can the user trash 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 trashing.
$post_trashed = wp_trash_post( $post_id );
if ( $post_trashed ) {
$trashed[] = $post_id;
} else {
$error[] = $post_id;
}
// Take a break periodically.
if ( 0 === $count++ % 50 ) {
stop_the_insanity();
sleep( 3 );
}
}
$results = compact( 'trashed', '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();
if ( isset( $_REQUEST[ self::ADMIN_NOTICE_KEY ] ) ) {
if ( 1 === (int) $_REQUEST[ self::ADMIN_NOTICE_KEY ] ) {
$class = 'notice-success';
$message = __( 'Success! The selected posts will be moved to the trash shortly.', 'bulk-edit-cron-offload' );
} else {
$class = 'notice-error';
$message = __( 'The selected posts are already scheduled to be moved to the trash.', 'bulk-edit-cron-offload' );
} elseif ( 'edit' === $screen->base ) {
if ( isset( $_REQUEST['post_status'] ) && 'trash' === $_REQUEST['post_status'] ) {
return;
}
$status = isset( $_REQUEST['post_status'] ) ? $_REQUEST['post_status'] : 'all';
if ( self::get_all_pending_actions( $screen->post_type, $status ) ) {
$class = 'notice-warning';
$message = __( 'Some items that would normally be shown here are waiting to be moved to the trash. These items are hidden until they are moved.', 'bulk-edit-cron-offload' );
}
}
// Nothing to display.
if ( ! isset( $class ) || ! isset( $message ) ) {
return;
}
?>
<div class="notice <?php echo esc_attr( $class ); ?>">
<p><?php echo esc_html( $message ); ?></p>
</div>
<?php
}
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
/**
* When a move 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_move( $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 = self::get_post_ids_pending_move( $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;
}
/**
* Gather all pending events for a given post type
*
* @param string $post_type Post type needing exclusion.
* @param string $post_status Post status to filter by.
* @return array
*/
private static function get_all_pending_actions( $post_type, $post_status ) {
$events = get_option( 'cron' );
if ( ! is_array( $events ) ) {
return array();
}
$ids = array();
foreach ( $events as $timestamp => $timestamp_events ) {
// Skip non-event data that Core includes in the option.
if ( ! is_numeric( $timestamp ) ) {
continue;
}
foreach ( $timestamp_events as $action => $action_instances ) {
if ( Main::CRON_EVENT !== $action ) {
continue;
}
foreach ( $action_instances as $instance => $instance_args ) {
$vars = array_shift( $instance_args['args'] );
if ( 'trash' === $vars->action && $post_type === $vars->post_type ) {
if ( $post_status === $vars->post_status || 'all' === $vars->post_status || 'all' === $post_status ) {
$ids[] = array(
'timestamp' => $timestamp,
'args' => $vars,
);
}
}
}
}
}
return $ids;
}
/**
* Gather IDs of objects pending move to trash, with given post type
*
* @param string $post_type Post type needing exclusion.
* @param string $post_status Post status to filter by.
* @return array
*/
private static function get_post_ids_pending_move( $post_type, $post_status ) {
$events = wp_list_pluck( self::get_all_pending_actions( $post_type, $post_status ), 'args' );
$events = wp_list_pluck( $events, 'posts' );
$ids = array();
foreach ( $events as $ids_to_merge ) {
$ids = array_merge( $ids, $ids_to_merge );
}
if ( ! empty( $ids ) ) {
$ids = array_map( 'absint', $ids );
$ids = array_unique( $ids );
}
return $ids;
}
}
Move_To_Trash::register_hooks();