PluginProbe ʕ •ᴥ•ʔ
Media Cleaner: Clean your WordPress! / 6.7.9
Media Cleaner: Clean your WordPress! v6.7.9
7.1.1 7.1.0 7.0.9 7.0.8 trunk 3.6.8 3.6.9 3.7.0 3.8.0 3.9.0 4.0.0 4.0.2 4.0.4 4.0.6 4.0.7 4.1.0 4.2.0 4.2.2 4.2.3 4.2.4 4.2.5 4.4.0 4.4.2 4.4.4 4.4.6 4.4.7 4.4.8 4.5.0 4.5.4 4.5.6 4.5.7 4.5.8 4.6.2 4.6.3 4.8.0 4.8.4 5.0.0 5.0.1 5.1.0 5.1.1 5.1.3 5.2.0 5.2.1 5.2.4 5.4.0 5.4.1 5.4.2 5.4.3 5.4.4 5.4.5 5.4.6 5.4.9 5.5.0 5.5.1 5.5.2 5.5.3 5.5.4 5.5.7 5.5.8 5.6.1 5.6.2 5.6.3 5.6.4 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.0.6 6.0.7 6.0.8 6.0.9 6.1.2 6.1.3 6.1.4 6.1.5 6.1.6 6.1.7 6.1.8 6.1.9 6.2.0 6.2.1 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.2.8 6.3.0 6.3.1 6.3.2 6.3.4 6.3.5 6.3.7 6.3.8 6.3.9 6.4.0 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.4.7 6.4.8 6.4.9 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.5.8 6.5.9 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.6.6 6.6.7 6.6.8 6.6.9 6.7.0 6.7.1 6.7.2 6.7.3 6.7.4 6.7.5 6.7.6 6.7.7 6.7.8 6.7.9 6.8.0 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.8.6 6.8.7 6.8.8 6.8.9 6.9.0 6.9.1 6.9.2 6.9.3 6.9.4 6.9.5 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.0.6 7.0.7
media-cleaner / classes / rest.php
media-cleaner / classes Last commit date
parsers 3 years ago admin.php 2 years ago core.php 1 year ago engine.php 2 years ago init.php 2 years ago parsers.php 5 years ago rest.php 2 years ago support.php 2 years ago ui.php 3 years ago
rest.php
872 lines
1 <?php
2
3 class Meow_WPMC_Rest
4 {
5 private $core = null;
6 private $admin = null;
7 private $engine = null;
8 private $namespace = 'media-cleaner/v1';
9
10 public function __construct( $core, $admin ) {
11 $this->core = $core;
12 $this->admin = $admin;
13 $this->engine = $core->engine;
14 add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
15 }
16
17 function rest_api_init() {
18 try {
19 // SETTINGS
20 register_rest_route( $this->namespace, '/update_options', array(
21 'methods' => 'POST',
22 'permission_callback' => array( $this->core, 'can_access_features' ),
23 'callback' => array( $this, 'rest_update_options' )
24 ) );
25 register_rest_route( $this->namespace, '/reset_options', array(
26 'methods' => 'POST',
27 'permission_callback' => array( $this->core, 'can_access_features' ),
28 'callback' => array( $this, 'rest_reset_options' )
29 ) );
30 register_rest_route( $this->namespace, '/all_settings', array(
31 'methods' => 'GET',
32 'permission_callback' => array( $this->core, 'can_access_features' ),
33 'callback' => array( $this, 'rest_all_settings' ),
34 ) );
35
36 // STATS & LISTING
37 register_rest_route( $this->namespace, '/count', array(
38 'methods' => 'POST',
39 'permission_callback' => array( $this->core, 'can_access_features' ),
40 'callback' => array( $this, 'rest_count' )
41 ) );
42 register_rest_route( $this->namespace, '/all_ids', array(
43 'methods' => 'POST',
44 'permission_callback' => array( $this->core, 'can_access_features' ),
45 'callback' => array( $this, 'rest_all_ids' ),
46 ) );
47 register_rest_route( $this->namespace, '/stats', array(
48 'methods' => 'GET',
49 'permission_callback' => array( $this->core, 'can_access_features' ),
50 'callback' => array( $this, 'rest_get_stats' ),
51 'args' => array(
52 'search' => array( 'required' => false ),
53 )
54 ) );
55 register_rest_route( $this->namespace, '/entries', array(
56 'methods' => 'GET',
57 'permission_callback' => array( $this->core, 'can_access_features' ),
58 'callback' => array( $this, 'rest_entries' ),
59 'args' => array(
60 'limit' => array( 'required' => false, 'default' => 10 ),
61 'skip' => array( 'required' => false, 'default' => 20 ),
62 'filterBy' => array( 'required' => false, 'default' => 'all' ),
63 'orderBy' => array( 'required' => false, 'default' => 'id' ),
64 'order' => array( 'required' => false, 'default' => 'desc' ),
65 'search' => array( 'required' => false ),
66 'repairMode' => array( 'required' => false, 'default' => false ),
67 )
68 ) );
69
70 // ACTIONS
71 register_rest_route( $this->namespace, '/set_ignore', array(
72 'methods' => 'POST',
73 'permission_callback' => array( $this->core, 'can_access_features' ),
74 'callback' => array( $this, 'rest_set_ignore' )
75 ) );
76 register_rest_route( $this->namespace, '/delete', array(
77 'methods' => 'POST',
78 'permission_callback' => array( $this->core, 'can_access_features' ),
79 'callback' => array( $this, 'rest_delete' )
80 ) );
81 register_rest_route( $this->namespace, '/recover', array(
82 'methods' => 'POST',
83 'permission_callback' => array( $this->core, 'can_access_features' ),
84 'callback' => array( $this, 'rest_recover' )
85 ) );
86 register_rest_route( $this->namespace, '/reset_db', array(
87 'methods' => 'POST',
88 'permission_callback' => array( $this->core, 'can_access_features' ),
89 'callback' => array( $this, 'rest_reset_db' )
90 ) );
91 register_rest_route( $this->namespace, '/repair', array(
92 'methods' => 'POST',
93 'permission_callback' => array( $this->core, 'can_access_features' ),
94 'callback' => array( $this, 'rest_repair' )
95 ) );
96
97 // SCAN
98 register_rest_route( $this->namespace, '/reset_issues', array(
99 'methods' => 'POST',
100 'permission_callback' => array( $this->core, 'can_access_features' ),
101 'callback' => array( $this, 'rest_reset_issues' )
102 ) );
103 register_rest_route( $this->namespace, '/reset_issues_and_references', array(
104 'methods' => 'POST',
105 'permission_callback' => array( $this->core, 'can_access_features' ),
106 'callback' => array( $this, 'rest_reset_issues_and_references' )
107 ) );
108 register_rest_route( $this->namespace, '/reset_references', array(
109 'methods' => 'POST',
110 'permission_callback' => array( $this->core, 'can_access_features' ),
111 'callback' => array( $this, 'rest_reset_references' )
112 ) );
113 register_rest_route( $this->namespace, '/extract_references', array(
114 'methods' => 'POST',
115 'permission_callback' => array( $this->core, 'can_access_features' ),
116 'callback' => array( $this, 'rest_extract_references' )
117 ) );
118 register_rest_route( $this->namespace, '/retrieve_medias', array(
119 'methods' => 'POST',
120 'permission_callback' => array( $this->core, 'can_access_features' ),
121 'callback' => array( $this, 'rest_retrieve_medias' )
122 ) );
123 register_rest_route( $this->namespace, '/retrieve_files', array(
124 'methods' => 'POST',
125 'permission_callback' => array( $this->core, 'can_access_features' ),
126 'callback' => array( $this, 'rest_retrieve_files' )
127 ) );
128 register_rest_route( $this->namespace, '/check_targets', array(
129 'methods' => 'POST',
130 'permission_callback' => array( $this->core, 'can_access_features' ),
131 'callback' => array( $this, 'rest_check_targets' )
132 ) );
133 register_rest_route( $this->namespace, '/uploads_directory_hierarchy', array(
134 'methods' => 'GET',
135 'permission_callback' => array( $this->core, 'can_access_features' ),
136 'callback' => array( $this, 'rest_uploads_directory_hierarchy' ),
137 'args' => array(
138 'force' => array( 'required' => false, 'default' => false ),
139 )
140 ) );
141
142 // LOGS
143 register_rest_route( $this->namespace, '/refresh_logs', array(
144 'methods' => 'POST',
145 'permission_callback' => array( $this->core, 'can_access_features' ),
146 'callback' => array( $this, 'rest_refresh_logs' )
147 ) );
148 register_rest_route( $this->namespace, '/clear_logs', array(
149 'methods' => 'POST',
150 'permission_callback' => array( $this->core, 'can_access_features' ),
151 'callback' => array( $this, 'rest_clear_logs' )
152 ) );
153 }
154 catch (Exception $e) {
155 var_dump($e);
156 }
157 }
158
159 /**
160 * Validates certain option values
161 * @param string $option Option name
162 * @param mixed $value Option value
163 * @return mixed|WP_Error Validated value if no problem
164 */
165 function validate_option( $option, $value ) {
166 switch ( $option ) {
167 case 'wpmc_dirs_filter':
168 case 'wpmc_files_filter':
169 if ( $value && @preg_match( $value, '' ) === false ) return new WP_Error( 'invalid_option', __( "Invalid Regular-Expression", 'media-cleaner' ) );
170 break;
171 }
172 return $value;
173 }
174
175 function rest_reset_issues() {
176 $this->core->reset_issues();
177 return new WP_REST_Response( [ 'success' => true, 'message' => __( 'Issues were reset.', 'media-cleaner' ) ], 200 );
178 }
179
180 function rest_reset_issues_and_references() {
181 $this->core->reset_issues();
182 $this->core->reset_references();
183 return new WP_REST_Response( [ 'success' => true, 'message' => __( 'Issues and References were reset.', 'media-cleaner' ) ], 200 );
184 }
185
186 function rest_reset_references() {
187 $this->core->reset_references();
188 return new WP_REST_Response( [ 'success' => true, 'message' => __( 'References were reset.', 'media-cleaner' ) ], 200 );
189 }
190
191 function rest_count( $request ) {
192 $params = $request->get_json_params();
193 $src = isset( $params['source'] ) ? $params['source'] : null;
194 $num = 0;
195 if ( $src === 'posts' ) {
196 $num = count( $this->engine->get_posts_to_check() );
197 }
198 else if ( $src === 'medias' ) {
199 $num = count( $this->engine->get_media_entries() );
200 }
201 else {
202 return new WP_REST_Response( [
203 'success' => false,
204 'message' => __( 'No source was mentioned while calling count.', 'media-cleaner' ),
205 ], 200 );
206 }
207 return new WP_REST_Response( [ 'success' => true, 'data' => $num ], 200 );
208 }
209
210 function rest_all_ids( $request ) {
211 $params = $request->get_json_params();
212 $src = isset( $params['source'] ) ? $params['source'] : null;
213 $search = isset( $params['search'] ) ? $params['search'] : null;
214 $repair_mode = isset( $params['repairMode'] ) ? rest_sanitize_boolean( $params['repairMode'] ) : false;
215 $ids = [];
216 if ( $src === 'issues' ) {
217 $ids = $repair_mode ? $this->core->get_repair_ids( $search ) : $this->get_issues_ids( $search );
218 }
219 else if ( $src === 'ignored' ) {
220 $ids = $this->get_ignored_ids( $search );
221 }
222 else if ( $src === 'trash' ) {
223 $ids = $this->get_trash_ids( $search );
224 }
225 else {
226 return new WP_REST_Response( [
227 'success' => false,
228 'message' => __( 'No source was mentioned while calling all_ids.', 'media-cleaner' ),
229 ], 200 );
230 }
231 return new WP_REST_Response( [ 'success' => true, 'data' => $ids ], 200 );
232 }
233
234 function rest_extract_references( $request ) {
235 $params = $request->get_json_params();
236 $limit = isset( $params['limit'] ) ? $params['limit'] : 0;
237 $source = isset( $params['source'] ) ? $params['source'] : null;
238 $post_id = isset( $params['postId'] ) ? $params['postId'] : null;
239 $limitsize = $this->core->get_option( 'posts_buffer' );
240 $finished = false;
241 $message = ""; // will be filled by extractRefsFrom...
242
243 // Randomly throw an exception
244 // if ( rand( 0, 2 ) !== 1 ) {
245 // throw new Exception( 'Random Exception' );
246 // }
247
248 if ( $post_id !== null && ( !is_numeric( $post_id ) || !is_int( (int) $post_id ) ) ) {
249 return new WP_REST_Response( [
250 'success' => false,
251 'message' => __( 'The postId parameter must be null or an integer.', 'media-cleaner' ),
252 ], 200 );
253 }
254
255 if ( $source === 'content' ) {
256 $finished = $this->engine->extractRefsFromContent( $limit, $limitsize, $message, $post_id );
257 }
258 else if ( $source === 'media' ) {
259 $finished = $this->engine->extractRefsFromLibrary( $limit, $limitsize, $message, $post_id );
260 }
261 else {
262 return new WP_REST_Response( [
263 'success' => false,
264 'message' => __( 'No source was mentioned while calling the extract_references action.', 'media-cleaner' ),
265 ], 200 );
266 }
267
268 $this->core->clean_ob();
269
270 return new WP_REST_Response( [
271 'success' => true,
272 'message' => $message,
273 'data' => [
274 'limit' => $limit + $limitsize,
275 'finished' => $finished,
276 ]
277 ], 200 );
278 }
279
280 function rest_retrieve_files( $request ) {
281 $params = $request->get_json_params();
282 $path = isset( $params['path'] ) ? ltrim( $params['path'], '/\\' ) : null;
283 $files = $this->engine->get_files( $path );
284 $files_count = count( $files );
285 $message = null;
286 if ( $files_count === 0 ) {
287 $message = sprintf( __( "No files for this path (%s).", 'media-cleaner' ), $path );
288 }
289 else {
290 $message = sprintf( __( "Retrieved %d targets.", 'media-cleaner' ), $files_count );
291 }
292 return new WP_REST_Response( [
293 'success' => true,
294 'message' => $message,
295 'data' => [
296 'results' => $files
297 ],
298 ], 200 );
299 }
300
301 function rest_retrieve_medias( $request ) {
302 $params = $request->get_json_params();
303 $limit = isset( $params['limit'] ) ? $params['limit'] : 0;
304 $limitsize = $this->core->get_option( 'medias_buffer' );
305 $unattachedOnly = $this->core->get_option( 'attach_is_use' );
306 $results = $this->engine->get_media_entries( $limit, $limitsize, $unattachedOnly );
307 $finished = count( $results ) < $limitsize;
308 $message = sprintf( __( "Retrieved %d targets.", 'media-cleaner' ), count( $results ) );
309
310 $this->core->clean_ob();
311
312 return new WP_REST_Response( [
313 'success' => true,
314 'message' => $message,
315 'data' => [
316 'limit' => $limit + $limitsize,
317 'finished' => $finished,
318 'results' => $results
319 ]
320 ], 200 );
321 }
322
323 function rest_check_targets( $request ) {
324 $params = $request->get_json_params();
325 // DEBUG: Simulate a timeout
326 // $this->core->deepsleep(10); header("HTTP/1.0 408 Request Timeout"); exit;
327
328 //ob_start();
329 $data = $params['targets'];
330 $method = $this->core->get_option( 'method' );
331
332 $this->core->timeout_check_start( count( $data ) );
333 $success = 0;
334 if ( $method == 'files' ) {
335 do_action( 'wpmc_check_file_init' ); // Build_CroppedFile_Cache() in pro core.php
336 }
337 foreach ( $data as $piece ) {
338 $this->core->timeout_check();
339 if ( $method == 'files' ) {
340 $this->core->log( "🔎 Checking File: {$piece}..." );
341 $result = ( $this->engine->check_file( $piece ) ? 1 : 0 );
342 if ( $result ) {
343 $success += $result;
344 }
345 // else {
346 // $this->core->log( "👻 Nothing found." );
347 // }
348 }
349 else if ( $method == 'media' ) {
350 $this->core->log( "🔎 Checking Media #{$piece}..." );
351 $result = ( $this->engine->check_media( $piece ) ? 1 : 0 );
352 if ( $result ) {
353 $success += $result;
354 }
355 // else {
356 // $this->core->log( "👻 Nothing found." );
357 // }
358 }
359 //$this->core->log();
360 $this->core->timeout_check_additem();
361 }
362 //ob_end_clean();
363 $elapsed = $this->core->timeout_get_elapsed();
364 $issues_found = count( $data ) - $success;
365 $message = sprintf(
366 // translators: %1$d is a number of targets, %2$d is a number of issues, %3$s is elapsed time in milliseconds
367 __( 'Checked %1$d targets and found %2$d issues in %3$s.', 'media-cleaner' ),
368 count( $data ), $issues_found, $elapsed
369 );
370
371 return new WP_REST_Response( [
372 'success' => true,
373 'message' => $message,
374 'results' => $success,
375 ], 200 );
376 }
377
378 function rest_refresh_logs() {
379 return new WP_REST_Response( [ 'success' => true, 'data' => $this->core->get_logs() ], 200 );
380 }
381
382 function rest_clear_logs() {
383 $this->core->clear_logs();
384 return new WP_REST_Response( [ 'success' => true ], 200 );
385 }
386
387 function rest_all_settings() {
388 return new WP_REST_Response( [
389 'success' => true,
390 'data' => array_merge( $this->core->get_all_options(), [
391 'incompatible_plugins' => !class_exists( 'MeowPro_WPMC_Core' ) ? Meow_WPMC_Support::get_issues() : []
392 ])
393 ], 200 );
394 }
395
396 function rest_update_options( $request ) {
397 try {
398 $params = $request->get_json_params();
399
400 if ( count( $params['options']) == 1 ) {
401 $this->core->log( "Ensuring the scan method: " . key( $params['options'] ) . " to " . $params['options'][ key( $params['options'] ) ] );
402
403 $options = $this->core->get_all_options();
404 $options[ key( $params['options'] ) ] = $params['options'][ key( $params['options'] ) ];
405 $params['options'] = $options;
406 }
407
408 $value = $params['options'];
409
410 $options = $this->core->update_options( $value );
411 $success = !!$options;
412 $message = __( $success ? 'OK' : "Could not update options.", 'media-cleaner' );
413 return new WP_REST_Response([ 'success' => $success, 'message' => $message, 'options' => $options ], 200 );
414 }
415 catch ( Exception $e ) {
416 return new WP_REST_Response([ 'success' => false, 'message' => $e->getMessage() ], 500 );
417 }
418 }
419
420 function rest_reset_options() {
421 $this->core->reset_options();
422 return new WP_REST_Response( [ 'success' => true, 'options' => $this->core->get_all_options() ], 200 );
423 }
424
425 function rest_reset_db() {
426 wpmc_reset();
427 return new WP_REST_Response( [ 'success' => true ], 200 );
428 }
429
430 function rest_reference_entries( $request ) {
431 global $wpdb;
432 $limit = sanitize_text_field( $request->get_param('limit') );
433 $skip = sanitize_text_field( $request->get_param('skip') );
434 $orderBy = sanitize_text_field( $request->get_param('orderBy') );
435 $order = sanitize_text_field( $request->get_param('order') );
436 $search = sanitize_text_field( $request->get_param('search') );
437 $referenceFilter = sanitize_text_field( $request->get_param('referenceFilter') );
438 $table_ref = $wpdb->prefix . "mclean_refs";
439
440 $total = $this->count_references($search, $referenceFilter);
441
442 $where_sql = '';
443 if ($referenceFilter === 'mediaIds') {
444 $where_sql = 'AND mediaId IS NOT NULL';
445 } else if ($referenceFilter === 'mediaUrls') {
446 $where_sql = 'AND mediaUrl IS NOT NULL';
447 }
448
449 $order_sql = 'ORDER BY id DESC';
450 if ( $orderBy === 'id' ) {
451 $order_sql = 'ORDER BY ID IS NULL, ID ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
452 } elseif ( $orderBy === 'mediaId' ) {
453 $order_sql = 'ORDER BY mediaId IS NULL, mediaId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
454 } elseif ( $orderBy === 'mediaUrl' ) {
455 $order_sql = 'ORDER BY mediaUrl IS NULL, mediaUrl ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
456 } elseif ( $orderBy === 'originType' ) {
457 $order_sql = 'ORDER BY originType ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
458 }
459
460 $entries = [];
461 if ( empty( $search ) ) {
462 $entries = $wpdb->get_results(
463 $wpdb->prepare( "SELECT *
464 FROM $table_ref
465 WHERE 1=1
466 $where_sql
467 $order_sql
468 LIMIT %d, %d", $skip, $limit
469 )
470 );
471 }
472 else {
473 $entries = $wpdb->get_results(
474 $wpdb->prepare( "SELECT *
475 FROM $table_ref
476 WHERE mediaUrl LIKE %s
477 $where_sql
478 $order_sql
479 LIMIT %d, %d", ( '%' . $search . '%' ), $skip, $limit
480 )
481 );
482 }
483
484 foreach ( $entries as $entry ) {
485 //Try and get a Post Title
486 $originType = $entry->originType;
487 preg_match( '/\[(.*?)\]/', $originType, $matches );
488 if ( isset( $matches[1] ) && is_numeric( $matches[1] ) ){
489 $id = $matches[1];
490 $post_title = get_the_title( $id );
491 if( $post_title ) {
492 $entry->post_title = $post_title;
493 }
494 }
495
496 // Try and get a Media URL (thumbnail)
497 $mediaId = $entry->mediaId;
498 if ( $mediaId ) {
499 $media = wp_get_attachment_image_src( $mediaId, 'thumbnail' );
500 if ( $media ) {
501 $entry->thumbnail = $media[0];
502 }
503 }
504
505 // Same but from MediaUrl if we didn't get one yet
506 $mediaUrl = $entry->mediaUrl;
507 if( $mediaUrl && empty( $entry->thumbnail ) ) {
508 // Get the ID of the attachment from its URL
509 $attachmentId = attachment_url_to_postid( $mediaUrl );
510
511 // Get the thumbnail of the attachment
512 $media = wp_get_attachment_image_src( $attachmentId, 'thumbnail' );
513 if ( $media ) {
514 $entry->thumbnail = $media[0];
515 }
516 }
517 }
518
519
520 return new WP_REST_Response( [ 'success' => true, 'data' => $entries, 'total' => $total ], 200 );
521 }
522
523 function rest_entries( $request ) {
524 global $wpdb;
525 $limit = sanitize_text_field( $request->get_param('limit') );
526 $skip = sanitize_text_field( $request->get_param('skip') );
527 $filterBy = sanitize_text_field( $request->get_param('filterBy') );
528 $orderBy = sanitize_text_field( $request->get_param('orderBy') );
529 $order = sanitize_text_field( $request->get_param('order') );
530 $search = sanitize_text_field( $request->get_param('search') );
531 $repair_mode = rest_sanitize_boolean( $request->get_param('repairMode') );
532 $table_scan = $wpdb->prefix . "mclean_scan";
533 $total = 0;
534
535 if ( $filterBy === 'references' ) {
536 return $this->rest_reference_entries( $request );
537 }
538
539 $entries = [];
540 if ( $repair_mode ) {
541 $entries = $this->core->get_issues_to_repair( $orderBy, $order, $search, $skip, $limit );
542 $total = $this->core->get_count_of_issues_to_repair( $search );
543 } else {
544 $whereSql = '';
545 if ( $filterBy == 'issues' ) {
546 $whereSql = 'WHERE ignored = 0 AND deleted = 0';
547 $total = $this->count_issues($search);
548 }
549 else if ( $filterBy == 'ignored' ) {
550 $whereSql = 'WHERE ignored = 1';
551 $total = $this->count_ignored($search);
552 }
553 else if ( $filterBy == 'trash' ) {
554 $whereSql = 'WHERE deleted = 1';
555 $total = $this->count_trash($search);
556 }
557 else {
558 $whereSql = 'WHERE deleted = 0';
559 }
560
561 $orderSql = 'ORDER BY id DESC';
562 if ( $orderBy === 'type' ) {
563 $orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
564 }
565 else if ( $orderBy === 'postId' ) {
566 $orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
567 }
568 $whereSql = '';
569 if ( $filterBy == 'issues' ) {
570 $whereSql = 'WHERE ignored = 0 AND deleted = 0';
571 $total = $this->count_issues($search);
572 }
573 else if ( $filterBy == 'ignored' ) {
574 $whereSql = 'WHERE ignored = 1';
575 $total = $this->count_ignored($search);
576 }
577 else if ( $filterBy == 'trash' ) {
578 $whereSql = 'WHERE deleted = 1';
579 $total = $this->count_trash($search);
580 }
581 else {
582 $whereSql = 'WHERE deleted = 0';
583 }
584
585 $orderSql = 'ORDER BY id DESC';
586 if ( $orderBy === 'type' ) {
587 $orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
588 }
589 else if ( $orderBy === 'postId' ) {
590 $orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
591 }
592 $whereSql = '';
593 if ( $filterBy == 'issues' ) {
594 $whereSql = 'WHERE ignored = 0 AND deleted = 0';
595 $total = $this->count_issues($search);
596 }
597 else if ( $filterBy == 'ignored' ) {
598 $whereSql = 'WHERE ignored = 1';
599 $total = $this->count_ignored($search);
600 }
601 else if ( $filterBy == 'trash' ) {
602 $whereSql = 'WHERE deleted = 1';
603 $total = $this->count_trash($search);
604 }
605 else {
606 $whereSql = 'WHERE deleted = 0';
607 }
608
609 $orderSql = 'ORDER BY id DESC';
610 if ( $orderBy === 'type' ) {
611 $orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
612 }
613 else if ( $orderBy === 'postId' ) {
614 $orderSql = 'ORDER BY postId ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
615 }
616 else if ( $orderBy === 'path' ) {
617 $orderSql = 'ORDER BY path ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
618 }
619 else if ( $orderBy === 'size' ) {
620 $orderSql = 'ORDER BY size ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
621 }
622
623 if ( empty( $search ) ) {
624 $entries = $wpdb->get_results(
625 $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
626 FROM $table_scan
627 $whereSql
628 $orderSql
629 LIMIT %d, %d", $skip, $limit
630 )
631 );
632 }
633 else {
634 $entries = $wpdb->get_results(
635 $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
636 FROM $table_scan
637 $whereSql
638 AND path LIKE %s
639 $orderSql
640 LIMIT %d, %d", ( '%' . $search . '%' ), $skip, $limit
641 )
642 );
643 }
644 }
645
646 $base = $filterBy == 'trash' ? $this->core->get_trashurl() : $this->core->upload_url;
647 foreach ( $entries as $entry ) {
648 // FILESYSTEM
649 if ( $entry->type == 0 ) {
650 $entry->thumbnail_url = htmlspecialchars( trailingslashit( $base ) . $entry->path, ENT_QUOTES );
651 $entry->image_url = $entry->thumbnail_url;
652 }
653 // MEDIA
654 else {
655 $attachment_src = wp_get_attachment_image_src( $entry->postId, 'thumbnail' );
656 $attachment_src_large = wp_get_attachment_image_src( $entry->postId, 'large' );
657 $thumbnail = empty( $attachment_src ) ? null : $attachment_src[0];
658 $image = empty( $attachment_src_large ) ? null : $attachment_src_large[0];
659 // This was working when the Post Type" was attachment"
660 if ( $filterBy == 'trash' && !empty( $thumbnail ) ) {
661 $new_url = $this->core->clean_url( $thumbnail );
662 $thumbnail = htmlspecialchars( trailingslashit( $base ) . $new_url, ENT_QUOTES );
663 }
664 if ( $filterBy == 'trash' && empty( $thumbnail ) ) {
665 $file = get_post_meta( $entry->postId, '_wp_attached_file', true );
666 $featured_image = wp_get_attachment_metadata( $entry->postId );
667 $thumbnail = "";
668 $image = htmlspecialchars( trailingslashit( $base ) . $file, ENT_QUOTES );
669 if ( isset( $featured_image['sizes']['thumbnail']['file'] ) ) {
670 $path = pathinfo( $file );
671 $thumbnail = $featured_image['sizes']['thumbnail']['file'];
672 $thumbnail = htmlspecialchars( trailingslashit( $base ) .
673 trailingslashit( $path['dirname'] ) . $thumbnail, ENT_QUOTES );
674 }
675 else {
676 $thumbnail = $image;
677 }
678 }
679 $entry->thumbnail_url = $thumbnail;
680 $entry->image_url = $image;
681 $entry->title = html_entity_decode( get_the_title( $entry->postId ) );
682 }
683 }
684
685 return new WP_REST_Response( [ 'success' => true, 'data' => $entries, 'total' => $total ], 200 );
686 }
687
688 function rest_set_ignore( $request ) {
689 $params = $request->get_json_params();
690 $ignore = (boolean)$params['ignore'];
691 $entryIds = isset( $params['entryIds'] ) ? (array)$params['entryIds'] : null;
692 $entryId = isset( $params['entryId'] ) ? (int)$params['entryId'] : null;
693 $data = null;
694 if ( !empty( $entryIds ) ) {
695 foreach ( $entryIds as $entryId ) {
696 $this->core->ignore( $entryId, $ignore );
697 }
698 $data = 'N/A';
699 }
700 else if ( !empty( $entryId ) ) {
701 $data = $this->core->ignore( $entryId, $ignore );
702 }
703 return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
704 }
705
706 function rest_delete( $request ) {
707 $params = $request->get_json_params();
708 $entryIds = isset( $params['entryIds'] ) ? (array)$params['entryIds'] : null;
709 $entryId = isset( $params['entryId'] ) ? (int)$params['entryId'] : null;
710 $data = null;
711 if ( !empty( $entryIds ) ) {
712 foreach ( $entryIds as $entryId ) {
713 $this->core->delete( $entryId );
714 }
715 $data = 'N/A';
716 }
717 else if ( !empty( $entryId ) ) {
718 $data = $this->core->delete( $entryId );
719 }
720 return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
721 }
722
723 function rest_recover( $request ) {
724 $params = $request->get_json_params();
725 $entryIds = isset( $params['entryIds'] ) ? (array)$params['entryIds'] : null;
726 $entryId = isset( $params['entryId'] ) ? (int)$params['entryId'] : null;
727 $data = null;
728 if ( !empty( $entryIds ) ) {
729 foreach ( $entryIds as $entryId ) {
730 $this->core->recover( $entryId );
731 }
732 $data = 'N/A';
733 }
734 else if ( !empty( $entryId ) ) {
735 $data = $this->core->recover( $entryId );
736 }
737 return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
738 }
739
740 function rest_repair( $request ) {
741 $params = $request->get_json_params();
742 $entryIds = isset( $params['entryIds'] ) ? (array)$params['entryIds'] : null;
743 $entryId = isset( $params['entryId'] ) ? (int)$params['entryId'] : null;
744 $data = null;
745 if ( !empty( $entryIds ) ) {
746 foreach ( $entryIds as $entryId ) {
747 $this->core->repair( $entryId );
748 }
749 $data = 'N/A';
750 }
751 else if ( !empty( $entryId ) ) {
752 $data = $this->core->repair( $entryId );
753 }
754 return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
755 }
756
757 function get_issues_ids($search) {
758 global $wpdb;
759 $whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
760 $table_scan = $wpdb->prefix . "mclean_scan";
761 return $wpdb->get_col( "SELECT ID FROM $table_scan WHERE ignored = 0 AND deleted = 0 $whereSql" );
762 }
763
764 function get_ignored_ids($search) {
765 global $wpdb;
766 $whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
767 $table_scan = $wpdb->prefix . "mclean_scan";
768 return $wpdb->get_col( "SELECT ID FROM $table_scan WHERE ignored = 1 $whereSql" );
769 }
770
771 function get_trash_ids($search) {
772 global $wpdb;
773 $whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
774 $table_scan = $wpdb->prefix . "mclean_scan";
775 return $wpdb->get_col( "SELECT ID FROM $table_scan WHERE deleted = 1 $whereSql" );
776 }
777
778 function count_issues($search) {
779 global $wpdb;
780 $whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
781 $table_scan = $wpdb->prefix . "mclean_scan";
782 return (int)$wpdb->get_var( "SELECT COUNT(*) FROM $table_scan WHERE ignored = 0 AND deleted = 0 $whereSql" );
783 }
784
785 function count_ignored($search) {
786 global $wpdb;
787 $whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
788 $table_scan = $wpdb->prefix . "mclean_scan";
789 return (int)$wpdb->get_var( "SELECT COUNT(*) FROM $table_scan WHERE ignored = 1 $whereSql" );
790 }
791
792 function count_trash($search) {
793 global $wpdb;
794 $whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
795 $table_scan = $wpdb->prefix . "mclean_scan";
796 return (int)$wpdb->get_var( "SELECT COUNT(*) FROM $table_scan WHERE deleted = 1 $whereSql" );
797 }
798
799 function count_references($search, $referenceFilter) {
800 global $wpdb;
801 $where_sqls = [];
802 if (! empty($search) ) {
803 $where_sqls[] = $wpdb->prepare("AND mediaUrl LIKE %s", ( '%' . $search . '%' ));
804 }
805 if ( $referenceFilter !== 'showAll' ) {
806 if ($referenceFilter === 'mediaIds') {
807 $where_sqls[] = 'AND mediaId IS NOT NULL';
808 } else if ($referenceFilter === 'mediaUrls') {
809 $where_sqls[] = 'AND mediaUrl IS NOT NULL';
810 }
811 }
812 $where_sql = implode(' ', $where_sqls);
813 $table_ref = $wpdb->prefix . "mclean_refs";
814 return (int)$wpdb->get_var( "SELECT COUNT(id) FROM $table_ref WHERE 1=1 $where_sql" );
815 }
816
817 function rest_get_stats( $request ) {
818 $search = sanitize_text_field( $request->get_param('search') );
819 $reference_filter = sanitize_text_field( $request->get_param('referenceFilter') );
820 $repair_mode = rest_sanitize_boolean( $request->get_param('repairMode') );
821
822 global $wpdb;
823 $whereSql = empty($search) ? '' : $wpdb->prepare("AND path LIKE %s", ( '%' . $search . '%' ));
824 $table_scan = $wpdb->prefix . "mclean_scan";
825 $issues = $repair_mode
826 ? $this->core->get_stats_of_issues_to_repair( $search )
827 : $wpdb->get_row( "SELECT COUNT(*) as entries, SUM(size) as size
828 FROM $table_scan WHERE ignored = 0 AND deleted = 0 $whereSql" );
829 $ignored = (int)$wpdb->get_var( "SELECT COUNT(*)
830 FROM $table_scan WHERE ignored = 1 $whereSql" );
831 $trash = $wpdb->get_row( "SELECT COUNT(*) as entries, SUM(size) as size
832 FROM $table_scan WHERE deleted = 1 $whereSql" );
833 $references = $this->count_references($search, $reference_filter);
834
835 return new WP_REST_Response( [ 'success' => true, 'data' => array(
836 'issues' => $issues->entries,
837 'issues_size' => $issues->size,
838 'ignored' => $ignored,
839 'trash' => $trash->entries,
840 'trash_size' => $trash->size,
841 'references' => $references,
842 ) ], 200 );
843 }
844
845 function rest_uploads_directory_hierarchy( $request ) {
846 if ( !$this->admin->is_pro_user() ) {
847 return new WP_REST_Response( [ 'success' => false, 'message' => __( 'This feature for Pro users.', 'media-cleaner' ) ], 200 );
848 }
849
850 $force = trim( $request->get_param('force') ) === 'true';
851 $transientKey = 'uploads_directory_hierarchy';
852 if ( $force ) {
853 delete_transient( $transientKey );
854 }
855
856 $data = get_transient( $transientKey );
857 $data = null;
858 if ( !$data ) {
859 $data = $this->core->get_uploads_directory_hierarchy();
860 set_transient( $transientKey, $data );
861 }
862
863 $uploads_dir = wp_upload_dir();
864 $root = wp_normalize_path( '/' . wp_basename( $uploads_dir['basedir'] ) );
865
866 return new WP_REST_Response( [ 'success' => true, 'data' => [
867 'root' => $root,
868 'hierarchy' => $data,
869 ] ] , 200 );
870 }
871 }
872