PluginProbe ʕ •ᴥ•ʔ
Media Cleaner: Clean your WordPress! / 4.5.6
Media Cleaner: Clean your WordPress! v4.5.6
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 / core.php
media-cleaner Last commit date
common 8 years ago core.php 8 years ago media-cleaner.css 9 years ago media-cleaner.js 8 years ago media-cleaner.php 8 years ago readme.txt 8 years ago wpmc_admin.php 8 years ago wpmc_checkers.php 8 years ago wpmc_custom_checkers.php 9 years ago wpmc_scan.php 8 years ago
core.php
1538 lines
1 <?php
2
3 class Meow_WPMC_Core {
4
5 public $checkers = null;
6 public $admin = null;
7 public $last_analysis = null;
8 public $last_analysis_ids = null;
9 public static $transient_life = 604800; // 7 days
10 private $regex_file = '/[A-Za-z0-9-_,\s]+[.]{1}(MIMETYPES)/';
11
12 public function __construct( $admin ) {
13 $this->admin = $admin;
14 add_action( 'admin_init', array( $this, 'admin_init' ) );
15 add_action( 'admin_menu', array( $this, 'admin_menu' ) );
16 add_action( 'admin_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ) );
17 add_action( 'admin_print_scripts', array( $this, 'admin_inline_js' ) );
18 add_action( 'wp_ajax_wpmc_scan', array( $this, 'wp_ajax_wpmc_scan' ) );
19 add_action( 'wp_ajax_wpmc_get_all_issues', array( $this, 'wp_ajax_wpmc_get_all_issues' ) );
20 add_action( 'wp_ajax_wpmc_get_all_deleted', array( $this, 'wp_ajax_wpmc_get_all_deleted' ) );
21 add_action( 'wp_ajax_wpmc_scan_do', array( $this, 'wp_ajax_wpmc_scan_do' ) );
22 add_action( 'wp_ajax_wpmc_prepare_do', array( $this, 'wp_ajax_wpmc_prepare_do' ) );
23 add_action( 'wp_ajax_wpmc_delete_do', array( $this, 'wp_ajax_wpmc_delete_do' ) );
24 add_action( 'wp_ajax_wpmc_ignore_do', array( $this, 'wp_ajax_wpmc_ignore_do' ) );
25 add_action( 'wp_ajax_wpmc_recover_do', array( $this, 'wp_ajax_wpmc_recover_do' ) );
26 add_filter( 'media_row_actions', array( $this, 'media_row_actions' ), 10, 2 );
27 add_action( 'add_meta_boxes', array( $this, 'add_metabox' ) );
28 }
29
30 function admin_init() {
31 $types = "jpg|jpeg|jpe|gif|png|tiff|bmp|csv|pdf|xls|xlsx|doc|docx|tiff|mp3|mp4|wav|lua";
32 $this->regex_file = str_replace( "MIMETYPES", $types, $this->regex_file );
33 require( 'wpmc_scan.php' );
34 require( 'wpmc_checkers.php' );
35 new MeowApps_WPMC_Scan( $this );
36 $this->checkers = new Meow_WPMC_Checkers( $this );
37 }
38
39 /*******************************************************************************
40 * METABOX FOR USAGE
41 ******************************************************************************/
42
43 function add_metabox() {
44 add_meta_box( 'mfrh_media_usage_box', 'Media Cleaner', array( $this, 'display_metabox' ), 'attachment', 'side', 'default' );
45 }
46
47 function display_metabox( $post ) {
48 $posts_images_urls = get_transient( "wpmc_posts_images_urls" );
49 if ( !is_array( $posts_images_urls ) ) {
50 echo "You need to run a Media Library scan first.";
51 return;
52 }
53 $this->log( "Media Edit > Checking Media #{$post->ID}" );
54 $success = $this->wpmc_check_media( $post->ID, true );
55 $this->log( "Success $success\n" );
56 if ( $success ) {
57 if ( $this->last_analysis == "CONTENT" ) {
58 echo "Found in content.";
59 }
60 else if ( $this->last_analysis == "CONTENT (ID)" ) {
61 echo "Found in content (as an ID).";
62 }
63 else if ( $this->last_analysis == "CONTENT (URL)" ) {
64 echo "Found in content (as an URL).";
65 }
66 else if ( $this->last_analysis == "THEME" ) {
67 echo "Found in theme.";
68 }
69 else if ( $this->last_analysis == "PAGE BUILDER" ) {
70 echo "Found in Page Builder.";
71 }
72 else if ( $this->last_analysis == "GALLERY" ) {
73 echo "Found in gallery.";
74 }
75 else if ( $this->last_analysis == "META" ) {
76 echo "Found in meta.";
77 }
78 else if ( $this->last_analysis == "META (ID)" ) {
79 echo "Found in meta (as an ID).";
80 }
81 else if ( $this->last_analysis == "META (URL)" ) {
82 echo "Found in meta (as an URL).";
83 }
84 else if ( $this->last_analysis == "META ACF (ID)" ) {
85 echo "Found in ACF meta (as an ID).";
86 }
87 else if ( $this->last_analysis == "META ACF (URL)" ) {
88 echo "Found in ACF meta (as an URL).";
89 }
90 else if ( $this->last_analysis == "WIDGET" ) {
91 echo "Found in widget.";
92 }
93 else {
94 echo $this->last_analysis;
95 }
96 }
97 else {
98 echo "Doesn't seem to be used.";
99 }
100 }
101
102 /*******************************************************************************
103 * ASYNCHRONOUS AJAX FUNCTIONS
104 ******************************************************************************/
105
106 function wp_ajax_wpmc_delete_do () {
107 ob_start();
108 $data = $_POST['data'];
109 $success = 0;
110 foreach ( $data as $piece ) {
111 $success += ( $this->wpmc_delete( $piece ) ? 1 : 0 );
112 }
113 ob_end_clean();
114 echo json_encode(
115 array(
116 'success' => true,
117 'result' => array( 'data' => $data, 'success' => $success ),
118 'message' => __( "Status unknown.", 'media-cleaner' )
119 )
120 );
121 die();
122 }
123
124 function wp_ajax_wpmc_ignore_do () {
125 ob_start();
126 $data = $_POST['data'];
127 $success = 0;
128 foreach ( $data as $piece ) {
129 $success += ( $this->wpmc_ignore( $piece ) ? 1 : 0 );
130 }
131 ob_end_clean();
132 echo json_encode(
133 array(
134 'success' => true,
135 'result' => array( 'data' => $data, 'success' => $success ),
136 'message' => __( "Status unknown.", 'media-cleaner' )
137 )
138 );
139 die();
140 }
141
142 function wp_ajax_wpmc_recover_do () {
143 ob_start();
144 $data = $_POST['data'];
145 $success = 0;
146 foreach ( $data as $piece ) {
147 $success += ( $this->wpmc_recover( $piece ) ? 1 : 0 );
148 }
149 ob_end_clean();
150 echo json_encode(
151 array(
152 'success' => true,
153 'result' => array( 'data' => $data, 'success' => $success ),
154 'message' => __( "Status unknown.", 'media-cleaner' )
155 )
156 );
157 die();
158 }
159
160 function wp_ajax_wpmc_scan_do () {
161 // For debug, to pretend there is a timeout
162 // header("HTTP/1.0 408 Request Timeout");
163 // exit;
164 ob_start();
165 $type = $_POST['type'];
166 $data = $_POST['data'];
167 $success = 0;
168 foreach ( $data as $piece ) {
169 if ( $type == 'file' ) {
170 $this->log( "Check File: {$piece}" );
171 $result = ( apply_filters( 'wpmc_check_file', true, $piece ) ? 1 : 0 );
172 $this->log( "Success " . $result . "\n" );
173 $success += $result;
174 } elseif ( $type == 'media' ) {
175 $this->log( "Checking Media #{$piece}" );
176 $result = ( $this->wpmc_check_media( $piece ) ? 1 : 0 );
177 $this->log( "Success " . $result . "\n" );
178 $success += $result;
179 }
180 }
181 ob_end_clean();
182 echo json_encode(
183 array(
184 'success' => true,
185 'result' => array( 'type' => $type, 'data' => $data, 'success' => $success ),
186 'message' => __( "Items checked.", 'media-cleaner' )
187 )
188 );
189 die();
190 }
191
192 function wp_ajax_wpmc_get_all_deleted () {
193 global $wpdb;
194 $table_name = $wpdb->prefix . "wpmcleaner";
195 $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 1" );
196 echo json_encode(
197 array(
198 'results' => array( 'ids' => $ids ),
199 'success' => true,
200 'message' => __( "List generated.", 'media-cleaner' )
201 )
202 );
203 die;
204 }
205
206 function wp_ajax_wpmc_get_all_issues () {
207 global $wpdb;
208 $isTrash = ( isset( $_POST['isTrash'] ) && $_POST['isTrash'] == 1 ) ? true : false;
209 $table_name = $wpdb->prefix . "wpmcleaner";
210 if ( $isTrash )
211 $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 1" );
212 else
213 $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 0" );
214 echo json_encode(
215 array(
216 'results' => array( 'ids' => $ids ),
217 'success' => true,
218 'message' => __( "List generated.", 'media-cleaner' )
219 )
220 );
221 die;
222 }
223
224 function array_to_ids_or_urls( &$meta, &$ids, &$urls ) {
225 foreach ( $meta as $k => $m ) {
226 if ( is_numeric( $m ) ) {
227 // Probably a Media ID
228 if ( $m > 0 )
229 array_push( $ids, $m );
230 }
231 else if ( is_array( $m ) ) {
232 // If it's an array with a width, probably that the index is the Media ID
233 if ( isset( $m['width'] ) && is_numeric( $k ) ) {
234 if ( $k > 0 )
235 array_push( $ids, $k );
236 }
237 }
238 else if ( !empty( $m ) ) {
239 // If it's a string, maybe it's a file (with an extension)
240 if ( preg_match($this->regex_file, $m ) )
241 array_push( $urls, $m );
242 }
243 }
244 }
245
246 function get_images_from_widgets( &$ids, &$urls ) {
247 global $wp_registered_widgets;
248 $syswidgets = $wp_registered_widgets;
249 $active_widgets = get_option( 'sidebars_widgets' );
250 foreach ( $active_widgets as $sidebar_name => $widgets ) {
251 if ( $sidebar_name != 'wp_inactive_widgets' && !empty( $widgets ) && is_array( $widgets ) ) {
252 $i = 0;
253 foreach ( $widgets as $key => $widget ) {
254 $widget_class = $syswidgets[$widget]['callback'][0]->option_name;
255 $instance_id = $syswidgets[$widget]['params'][0]['number'];
256 $widget_data = get_option( $widget_class );
257 // error_log( "INSTANCE $key ($instance_id)" );
258 // error_log( print_r( $widget_data, 1 ) );
259 if ( !empty( $widget_data[$instance_id]['text'] ) ) {
260 $html = do_shortcode( $widget_data[$instance_id]['text'] );
261 $urls = array_merge( $urls, $this->get_urls_from_html( $html ) );
262 }
263 if ( !empty( $widget_data[$instance_id]['attachment_id'] ) ) {
264 $id = $widget_data[$instance_id]['attachment_id'];
265 array_push( $ids, $id );
266 }
267 if ( !empty( $widget_data[$instance_id]['url'] ) ) {
268 $url = $this->wpmc_clean_url( $widget_data[$instance_id]['url'] );
269 array_push( $urls, $url );
270 }
271 if ( !empty( $widget_data[$instance_id]['ids'] ) ) {
272 $newIds = $widget_data[$instance_id]['ids'];
273 $ids = array_merge( $ids, $newIds );
274 }
275 $i++;
276 }
277 }
278 }
279 }
280
281 function get_urls_from_html( $html ) {
282 if ( empty( $html ) )
283 return array();
284 libxml_use_internal_errors( false );
285
286 $dom = new DOMDocument();
287 @$dom->loadHTML( $html );
288
289 // Images, src, srcset
290 $imgs = $dom->getElementsByTagName( 'img' );
291 $results = array();
292 foreach ( $imgs as $img ) {
293 $src = $this->wpmc_clean_url( $img->getAttribute('src') );
294 array_push( $results, $src );
295 $srcset = $img->getAttribute('srcset');
296 if ( !empty( $srcset ) ) {
297 $setImgs = explode( ',', trim( $srcset ) );
298 foreach ( $setImgs as $setImg ) {
299 $finalSetImg = explode( ' ', trim( $setImg ) );
300 if ( is_array( $finalSetImg ) ) {
301 array_push( $results, $this->wpmc_clean_url( $finalSetImg[0] ) );
302 }
303 }
304 }
305 }
306
307 // Links, href
308 $urls = $dom->getElementsByTagName( 'a' );
309 foreach ( $urls as $url ) {
310 $src = $this->wpmc_clean_url( $url->getAttribute('href') );
311 array_push( $results, $src );
312 }
313
314 // if ( get_option( 'wpmc_background', false ) ) {
315 preg_match_all( "/url\(\'?\"?((https?:\/\/)?[^\\&\#\[\] \"\?]+\.(jpe?g|gif|png))\'?\"?/", $html, $res );
316 //error_log( print_r( $res, 1 ) );
317 if ( !empty( $res ) && isset( $res[1] ) && count( $res[1] ) > 0 ) {
318 foreach ( $res[1] as $url ) {
319 array_push( $results, $this->wpmc_clean_url( $url ) );
320 }
321 }
322 // }
323
324 return $results;
325 }
326
327 // Parse a meta, visit all the arrays, look for the attributes, fill $ids and $urls arrays
328 function get_from_meta( $meta, $lookFor, &$ids, &$urls ) {
329 foreach ( $meta as $key => $value ) {
330 if ( is_object( $value ) || is_array( $value ) )
331 $this->get_from_meta( $value, $lookFor, $ids, $urls );
332 else if ( in_array( $key, $lookFor ) ) {
333 if ( empty( $value ) )
334 continue;
335 else if ( is_numeric( $value ) )
336 array_push( $ids, $value );
337 else
338 array_push( $urls, $this->wpmc_clean_url( $value ) );
339 }
340 }
341 }
342
343 function get_images_from_themes( &$ids, &$urls ) {
344 global $wpdb;
345
346 // USE CURRENT THEME AND WP API
347 $ch = get_custom_header();
348 if ( !empty( $ch ) && !empty( $ch->url ) ) {
349 array_push( $urls, $this->wpmc_clean_url( $ch->url ) );
350 }
351 if ( !empty( $ch ) && !empty( $ch->attachment_id ) ) {
352 array_push( $ids, $ch->attachment_id );
353 }
354 $cl = get_custom_logo();
355 if ( !empty( $cl ) ) {
356 $urls = array_merge( $this->get_urls_from_html( $cl ), $urls );
357 }
358 $cd = get_background_image();
359 if ( !empty( $cd ) ) {
360 array_push( $urls, $this->wpmc_clean_url( $cd ) );
361 }
362 $photography_hero_image = get_theme_mod( 'photography_hero_image' );
363 if ( !empty( $photography_hero_image ) ) {
364 array_push( $ids, $photography_hero_image );
365 }
366 $author_profile_picture = get_theme_mod( 'author_profile_picture' );
367 if ( !empty( $author_profile_picture ) ) {
368 array_push( $ids, $author_profile_picture );
369 }
370 }
371
372 function wp_ajax_wpmc_prepare_do() {
373 $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
374 $limitsize = get_option( 'wpmc_posts_buffer', 5 );
375 if ( empty( $limit ) )
376 $this->wpmc_reset_issues();
377
378 $method = get_option( 'wpmc_method', 'media' );
379 $check_library = get_option(' wpmc_media_library', true );
380 $check_postmeta = get_option( 'wpmc_postmeta', false );
381 $check_posts = get_option( 'wpmc_posts', false );
382 $check_widgets = get_option( 'wpmc_widgets', false );
383 if ( $method == 'media' && !$check_posts && !$check_postmeta && !$check_widgets ) {
384 echo json_encode( array(
385 'results' => array(),
386 'success' => true,
387 'finished' => true,
388 'message' => __( "Posts, Meta and Widgets analysis are all off. Done.", 'media-cleaner' )
389 ) );
390 die();
391 }
392 if ( $method == 'files' && $check_library && !$check_posts && !$check_postmeta && !$check_widgets ) {
393 echo json_encode( array(
394 'results' => array(),
395 'success' => true,
396 'finished' => true,
397 'message' => __( "Posts, Meta and Widgets analysis are all off. Done.", 'media-cleaner' )
398 ) );
399 die();
400 }
401
402 global $wpdb;
403 // Maybe we could avoid to check more post_types.
404 // SELECT post_type, COUNT(*) FROM `wp_posts` GROUP BY post_type
405 $posts = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
406 WHERE p.post_status != 'inherit'
407 AND p.post_status != 'trash'
408 AND p.post_type != 'attachment'
409 AND p.post_type NOT LIKE '%acf-%'
410 AND p.post_type NOT LIKE '%edd_%'
411 AND p.post_type != 'shop_order'
412 AND p.post_type != 'shop_order_refund'
413 AND p.post_type != 'nav_menu_item'
414 AND p.post_type != 'revision'
415 AND p.post_type != 'auto-draft'
416 LIMIT %d, %d", $limit, $limitsize
417 )
418 );
419
420 $found = array();
421
422 if ( empty( $limit ) ) {
423 $theme_ids = array();
424 $theme_urls = array();
425 $this->get_images_from_themes( $theme_ids, $theme_urls );
426 set_transient( "wpmc_theme_ids", $theme_ids, Meow_WPMC_Core::$transient_life );
427 set_transient( "wpmc_theme_urls", $theme_urls, Meow_WPMC_Core::$transient_life );
428 $found['wpmc_theme_ids'] = $theme_ids;
429 $found['wpmc_theme_urls'] = $theme_urls;
430 }
431
432 // Only on Start: Analyze Widgets
433 if ( get_option( 'wpmc_widgets', false ) && empty( $limit ) ) {
434 $widgets_ids = array();
435 $widgets_urls = array();
436 $this->get_images_from_widgets( $widgets_ids, $widgets_urls );
437 set_transient( "wpmc_widgets_ids", $widgets_ids, Meow_WPMC_Core::$transient_life );
438 set_transient( "wpmc_widgets_urls", $widgets_urls, Meow_WPMC_Core::$transient_life );
439 $found['wpmc_widgets_ids'] = $widgets_ids;
440 $found['wpmc_widgets_urls'] = $widgets_urls;
441 }
442
443 // Only on Start: Analyze WooCommerce Categories Images
444 if ( class_exists( 'WooCommerce' ) && empty( $limit ) ) {
445 $metas = $wpdb->get_col( "SELECT meta_value
446 FROM $wpdb->termmeta
447 WHERE meta_key LIKE '%thumbnail_id%'"
448 );
449 if ( count( $metas ) > 0 ) {
450 $postmeta_images_ids = get_transient( "wpmc_postmeta_images_ids" );
451 if ( empty( $postmeta_images_ids ) )
452 $postmeta_images_ids = array();
453 foreach ( $metas as $meta )
454 if ( is_numeric( $meta ) && $meta > 0 )
455 array_push( $postmeta_images_ids, $meta );
456 set_transient( "wpmc_postmeta_images_ids", $postmeta_images_ids, Meow_WPMC_Core::$transient_life );
457 $found['wpmc_postmeta_images_ids'] = $postmeta_images_ids;
458 }
459 }
460
461 // Analyze Posts
462 foreach ( $posts as $post ) {
463
464 // Get HTML for this post
465 $html = get_post_field( 'post_content', $post );
466 $html = do_shortcode( $html );
467 $html = wp_make_content_images_responsive( $html );
468
469 // Run the scanners
470 if ( $check_postmeta )
471 do_action( 'wpmc_scan_postmeta', $post );
472 if ( $check_posts )
473 do_action( "wpmc_scan_post", $html, $post );
474 }
475 $finished = count( $posts ) < $limitsize;
476 if ( $finished ) {
477 $found = array();
478
479 $theme_urls = get_transient( "wpmc_theme_urls" );
480 $theme_ids = get_transient( "wpmc_theme_ids" );
481 $widgets_urls = get_transient( "wpmc_widgets_urls" );
482 $widgets_ids = get_transient( "wpmc_widgets_ids" );
483 $posts_images_urls = get_transient( "wpmc_posts_images_urls" );
484 $posts_images_ids = get_transient( "wpmc_posts_images_ids" );
485 $postmeta_images_urls = get_transient( "wpmc_postmeta_images_urls" );
486 $postmeta_images_ids = get_transient( "wpmc_postmeta_images_ids" );
487 $postmeta_images_acf_urls = get_transient( "wpmc_postmeta_images_acf_urls" );
488 $postmeta_images_acf_ids = get_transient( "wpmc_postmeta_images_acf_ids" );
489 $posts_images_vc = get_transient( "wpmc_posts_images_visualcomposer" );
490 $galleries_images_urls = get_transient( "wpmc_galleries_images_urls" );
491 $galleries_images_vc = get_transient( "wpmc_galleries_images_visualcomposer" );
492 $galleries_images_fb = get_transient( "wpmc_galleries_images_fusionbuilder" );
493 $galleries_images_wc = get_transient( "wpmc_galleries_images_woocommerce" );
494 $galleries_images_et = get_transient( "wpmc_galleries_images_divi" );
495
496 $found['theme_urls'] = is_array( $theme_urls ) ? array_unique( $theme_urls ) : array();
497 $found['widgets_urls'] = is_array( $widgets_urls ) ? array_unique( $widgets_urls ) : array();
498 $found['posts_images_urls'] = is_array( $posts_images_urls ) ? array_unique( $posts_images_urls ) : array();
499 $found['postmeta_images_urls'] = is_array( $postmeta_images_urls ) ? array_unique( $postmeta_images_urls ) : array();
500 $found['postmeta_images_acf_urls'] = is_array( $postmeta_images_acf_urls ) ? array_unique( $postmeta_images_acf_urls ) : array();
501 $found['galleries_images_urls'] = is_array( $galleries_images_urls ) ? array_unique( $galleries_images_urls ) : array();
502
503 $found['theme_ids'] = is_array( $theme_ids ) ? array_unique( $theme_ids ) : array();
504 $found['widgets_ids'] = is_array( $widgets_ids ) ? array_unique( $widgets_ids ) : array();
505 $found['posts_images_ids'] = is_array( $posts_images_ids ) ? array_unique( $posts_images_ids ) : array();
506 $found['postmeta_images_ids'] = is_array( $postmeta_images_ids ) ? array_unique( $postmeta_images_ids ) : array();
507 $found['postmeta_images_acf_ids'] = is_array( $postmeta_images_acf_ids ) ? array_unique( $postmeta_images_acf_ids ) : array();
508 $found['posts_images_vc'] = is_array( $posts_images_vc ) ? array_unique( $posts_images_vc ) : array();
509 $found['galleries_images_vc'] = is_array( $galleries_images_vc ) ? array_unique( $galleries_images_vc ) : array();
510 $found['galleries_images_fb'] = is_array( $galleries_images_fb ) ? array_unique( $galleries_images_fb ) : array();
511 $found['galleries_images_wc'] = is_array( $galleries_images_wc ) ? array_unique( $galleries_images_wc ) : array();
512 $found['galleries_images_et'] = is_array( $galleries_images_et ) ? array_unique( $galleries_images_et ) : array();
513
514 // For safety, remove the resolutions...
515 // That will match more files, especially the sizes created before, used before, but not part of the
516 // media metadata anymore.
517
518 // ADD AN OPTION "CHECK SKIP RESOLUTION" (DEFAULT TRUE)
519 $method = get_option( 'wpmc_method', 'media' );
520 if ( $method == 'media' ) {
521 // All URLs should be without resolution to make sure it matches Media
522 array_walk( $found['theme_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
523 array_walk( $found['widgets_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
524 array_walk( $found['posts_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
525 array_walk( $found['postmeta_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
526 array_walk( $found['postmeta_images_acf_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
527 array_walk( $found['galleries_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
528 }
529 else {
530 // We need both filename without resolution and filename with resolution, it's important
531 // to make sure the original file is not deleted if a size exists for it
532 $clone = $found['theme_urls'];
533 array_walk( $found['theme_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
534 $found['theme_urls'] = array_merge( $clone, $found['theme_urls'] );
535 $clone = $found['widgets_urls'];
536 array_walk( $found['widgets_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
537 $found['widgets_urls'] = array_merge( $clone, $found['widgets_urls'] );
538 $clone = $found['posts_images_urls'];
539 array_walk( $found['posts_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
540 $found['posts_images_urls'] = array_merge( $clone, $found['posts_images_urls'] );
541 $clone = $found['postmeta_images_urls'];
542 array_walk( $found['postmeta_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
543 $found['postmeta_images_urls'] = array_merge( $clone, $found['postmeta_images_urls'] );
544 $clone = $found['postmeta_images_acf_urls'];
545 array_walk( $found['postmeta_images_acf_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
546 $found['postmeta_images_acf_urls'] = array_merge( $clone, $found['postmeta_images_acf_urls'] );
547 $clone = $found['galleries_images_urls'];
548 array_walk( $found['galleries_images_urls'], array( $this, 'clean_url_from_resolution_ref' ) );
549 $found['galleries_images_urls'] = array_merge( $clone, $found['galleries_images_urls'] );
550 }
551
552 set_transient( "wpmc_theme_urls", $found['theme_urls'], Meow_WPMC_Core::$transient_life );
553 set_transient( "wpmc_theme_ids", $found['theme_ids'], Meow_WPMC_Core::$transient_life );
554 set_transient( "wpmc_widgets_urls", $found['widgets_urls'], Meow_WPMC_Core::$transient_life );
555 set_transient( "wpmc_widgets_ids", $found['widgets_ids'], Meow_WPMC_Core::$transient_life );
556 set_transient( "wpmc_posts_images_urls", $found['posts_images_urls'], Meow_WPMC_Core::$transient_life );
557 set_transient( "wpmc_posts_images_ids", $found['posts_images_ids'], Meow_WPMC_Core::$transient_life );
558 set_transient( "wpmc_postmeta_images_urls", $found['postmeta_images_urls'], Meow_WPMC_Core::$transient_life );
559 set_transient( "wpmc_postmeta_images_ids", $found['postmeta_images_ids'], Meow_WPMC_Core::$transient_life );
560 set_transient( "wpmc_postmeta_images_acf_urls", $found['postmeta_images_acf_urls'], Meow_WPMC_Core::$transient_life );
561 set_transient( "wpmc_postmeta_images_acf_ids", $found['postmeta_images_acf_ids'], Meow_WPMC_Core::$transient_life );
562 set_transient( "wpmc_posts_images_visualcomposer", $found['posts_images_vc'], Meow_WPMC_Core::$transient_life );
563 set_transient( "wpmc_galleries_images_visualcomposer", $found['galleries_images_vc'], Meow_WPMC_Core::$transient_life );
564 set_transient( "wpmc_galleries_images_fusionbuilder", $found['galleries_images_fb'], Meow_WPMC_Core::$transient_life );
565 set_transient( "wpmc_galleries_images_woocommerce", $found['galleries_images_wc'], Meow_WPMC_Core::$transient_life );
566 set_transient( "wpmc_galleries_images_divi", $found['galleries_images_et'], Meow_WPMC_Core::$transient_life );
567 set_transient( "wpmc_galleries_images_urls", $found['galleries_images_urls'], Meow_WPMC_Core::$transient_life );
568 }
569 if ( $finished && get_option( 'wpmc_debuglogs', false ) ) {
570 $this->log( print_r( $found, true ) );
571 }
572 echo json_encode(
573 array(
574 'success' => true,
575 'finished' => $finished,
576 'limit' => $limit + $limitsize,
577 'found' => $found,
578 'message' => __( "Posts checked.", 'media-cleaner' ) )
579 );
580 die();
581 }
582
583 function log( $data, $force = false ) {
584 if ( !get_option( 'wpmc_debuglogs', false ) && !$force )
585 return;
586 $fh = @fopen( trailingslashit( dirname(__FILE__) ) . '/media-cleaner.log', 'a' );
587 if ( !$fh )
588 return false;
589 $date = date( "Y-m-d H:i:s" );
590 fwrite( $fh, "$date: {$data}\n" );
591 fclose( $fh );
592 return true;
593 }
594
595 function wp_ajax_wpmc_scan() {
596 global $wpdb;
597
598 $method = get_option( 'wpmc_method', 'media' );
599 if ( !$this->admin->is_registered() )
600 $method = 'media';
601 $path = isset( $_POST['path'] ) ? $_POST['path'] : null;
602 $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
603 $limitsize = get_option( 'wpmc_medias_buffer', 100 );
604
605 if ( $method == 'files' ) {
606 $output = apply_filters( 'wpmc_list_uploaded_files', array(
607 'results' => array(), 'success' => false, 'message' => __( "Unavailable.", 'media-cleaner' )
608 ), $path );
609 echo json_encode( $output );
610 die();
611 }
612
613 if ( $method == 'media' ) {
614 // Prevent double scanning by removing filesystem entries that we have DB entries for
615 $results = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
616 WHERE p.post_status = 'inherit'
617 AND p.post_type = 'attachment'
618 LIMIT %d, %d", $limit, $limitsize
619 )
620 );
621 $finished = count( $results ) < $limitsize;
622 echo json_encode(
623 array(
624 'results' => $results,
625 'success' => true,
626 'finished' => $finished,
627 'limit' => $limit + $limitsize,
628 'message' => __( "Medias retrieved.", 'media-cleaner' ) )
629 );
630 die();
631 }
632
633 // No task.
634 echo json_encode( array( 'success' => false, 'message' => __( "No task.", 'media-cleaner' ) ) );
635 die();
636 }
637
638 /**
639 *
640 * HELPERS
641 *
642 */
643
644 function wpmc_trashdir() {
645 $upload_folder = wp_upload_dir();
646 return trailingslashit( $upload_folder['basedir'] ) . 'wpmc-trash';
647 }
648
649 function wpmc_check_db() {
650 global $wpdb;
651 $tbl_m = $wpdb->prefix . 'wpmcleaner';
652 if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(1) FROM information_schema.tables WHERE table_schema = '%s' AND table_name = '%s';", $wpdb->dbname, $tbl_m ) ) ) {
653 wpmc_activate();
654 }
655 }
656
657 /**
658 *
659 * DELETE / SCANNING / RESET
660 *
661 */
662
663 function wpmc_recover_file( $path ) {
664 $basedir = wp_upload_dir();
665 $originalPath = trailingslashit( $basedir['basedir'] ) . $path;
666 $trashPath = trailingslashit( $this->wpmc_trashdir() ) . $path;
667 $path_parts = pathinfo( $originalPath );
668 if ( !file_exists( $path_parts['dirname'] ) && !wp_mkdir_p( $path_parts['dirname'] ) ) {
669 die( 'Failed to create folder.' );
670 }
671 if ( !file_exists( $trashPath ) ) {
672 $this->log( "The file $originalPath actually does not exist in the trash." );
673 return true;
674 }
675 if ( !rename( $trashPath, $originalPath ) ) {
676 die( 'Failed to move the file.' );
677 }
678 return true;
679 }
680
681 function wpmc_recover( $id ) {
682 global $wpdb;
683 $table_name = $wpdb->prefix . "wpmcleaner";
684 $issue = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ), OBJECT );
685 $issue->path = stripslashes( $issue->path );
686
687 // Files
688 if ( $issue->type == 0 ) {
689 $this->wpmc_recover_file( $issue->path );
690 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 0 WHERE id = %d", $id ) );
691 return true;
692 }
693 // Media
694 else if ( $issue->type == 1 ) {
695
696 // Copy the main file back
697 $fullpath = get_attached_file( $issue->postId );
698 if ( empty( $fullpath ) ) {
699 error_log( "Media {$issue->postId} does not have attached file anymore." );
700 return false;
701 }
702 $mainfile = $this->wpmc_clean_uploaded_filename( $fullpath );
703 $baseUp = pathinfo( $mainfile );
704 $baseUp = $baseUp['dirname'];
705 $file = $this->wpmc_clean_uploaded_filename( $fullpath );
706 if ( !$this->wpmc_recover_file( $file ) ) {
707 $this->log( "Could not recover $file." );
708 error_log( "Media Cleaner: Could not recover $file." );
709 }
710
711 // If images, copy the other files as well
712 $meta = wp_get_attachment_metadata( $issue->postId );
713 $isImage = isset( $meta, $meta['width'], $meta['height'] );
714 $sizes = $this->wpmc_get_image_sizes();
715 if ( $isImage && isset( $meta['sizes'] ) ) {
716 foreach ( $meta['sizes'] as $name => $attr ) {
717 if ( isset( $attr['file'] ) ) {
718 $filepath = wp_upload_dir();
719 $filepath = $filepath['basedir'];
720 $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
721 $file = $this->wpmc_clean_uploaded_filename( $filepath );
722 if ( !$this->wpmc_recover_file( $file ) ) {
723 $this->log( "Could not recover $file." );
724 error_log( "Media Cleaner: Could not recover $file." );
725 }
726 }
727 }
728 }
729 if ( !wp_untrash_post( $issue->postId ) ) {
730 error_log( "Cleaner: Failed to Untrash Post {$issue->postId} (but deleted it from Cleaner DB)." );
731 }
732 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 0 WHERE id = %d", $id ) );
733 return true;
734 }
735 }
736
737 function wpmc_trash_file( $fileIssuePath ) {
738 global $wpdb;
739 $basedir = wp_upload_dir();
740 $originalPath = trailingslashit( $basedir['basedir'] ) . $fileIssuePath;
741 $trashPath = trailingslashit( $this->wpmc_trashdir() ) . $fileIssuePath;
742 $path_parts = pathinfo( $trashPath );
743
744 try {
745 if ( !file_exists( $path_parts['dirname'] ) && !wp_mkdir_p( $path_parts['dirname'] ) ) {
746 $this->log( "Could not create the trash directory for Media Cleaner." );
747 error_log( "Media Cleaner: Could not create the trash directory." );
748 return false;
749 }
750 // Rename the file (move). 'is_dir' is just there for security (no way we should move a whole directory)
751 if ( is_dir( $originalPath ) ) {
752 $this->log( "Attempted to delete a directory instead of a file ($originalPath). Can't do that." );
753 error_log( "Media Cleaner: Attempted to delete a directory instead of a file ($originalPath). Can't do that." );
754 return false;
755 }
756 if ( !file_exists( $originalPath ) ) {
757 $this->log( "The file $originalPath actually does not exist." );
758 return true;
759 }
760 if ( !@rename( $originalPath, $trashPath ) ) {
761 return false;
762 }
763 }
764 catch ( Exception $e ) {
765 return false;
766 }
767 $this->wpmc_clean_dir( dirname( $originalPath ) );
768 return true;
769 }
770
771 function wpmc_ignore( $id ) {
772 global $wpdb;
773 $table_name = $wpdb->prefix . "wpmcleaner";
774 $has = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $table_name WHERE id = %d AND ignored = 1", $id ) );
775 if ( $has > 0 )
776 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET ignored = 0 WHERE id = %d", $id ) );
777 else
778 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET ignored = 1 WHERE id = %d", $id ) );
779 return true;
780 }
781
782 function wpmc_endsWith( $haystack, $needle )
783 {
784 $length = strlen( $needle );
785 if ( $length == 0 )
786 return true;
787 return ( substr( $haystack, -$length ) === $needle );
788 }
789
790 function wpmc_clean_dir( $dir ) {
791 if ( !file_exists( $dir ) )
792 return;
793 else if ( $this->wpmc_endsWith( $dir, 'uploads' ) )
794 return;
795 $found = array_diff( scandir( $dir ), array( '.', '..' ) );
796 if ( count( $found ) < 1 ) {
797 if ( rmdir( $dir ) ) {
798 $this->wpmc_clean_dir( dirname( $dir ) );
799 }
800 }
801 }
802
803 function wpmc_delete( $id ) {
804 global $wpdb;
805 $table_name = $wpdb->prefix . "wpmcleaner";
806 $issue = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ), OBJECT );
807 $regex = "^(.*)(\\s\\(\\+.*)$";
808 $issue->path = preg_replace( '/' . $regex . '/i', '$1', $issue->path ); // remove " (+ 6 files)" from path
809
810 // Make sure there isn't a media DB entry
811 if ( $issue->type == 0 ) {
812 $attachmentid = $this->wpmc_find_attachment_id_by_file( $issue->path );
813 if ( $attachmentid ) {
814 $this->log( "Issue listed as filesystem but Media {$attachmentid} exists." );
815 }
816 }
817
818 if ( $issue->type == 0 ) {
819
820 if ( $issue->deleted == 0 ) {
821 // Move file to the trash
822 if ( $this->wpmc_trash_file( $issue->path ) )
823 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 1 WHERE id = %d", $id ) );
824 return true;
825 }
826 else {
827 // Delete file from the trash
828 $trashPath = trailingslashit( $this->wpmc_trashdir() ) . $issue->path;
829 if ( !unlink( $trashPath ) ) {
830 $this->log( "Failed to delete the file." );
831 error_log( "Media Cleaner: Failed to delete the file." );
832 }
833 $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE id = %d", $id ) );
834 $this->wpmc_clean_dir( dirname( $trashPath ) );
835 return true;
836 }
837 }
838
839 if ( $issue->type == 1 ) {
840 if ( $issue->deleted == 0 && MEDIA_TRASH ) {
841 // Move Media to trash
842 // Let's copy the images to the trash so that it can be recovered.
843 $fullpath = get_attached_file( $issue->postId );
844 $mainfile = $this->wpmc_clean_uploaded_filename( $fullpath );
845 $baseUp = pathinfo( $mainfile );
846 $baseUp = $baseUp['dirname'];
847 $file = $this->wpmc_clean_uploaded_filename( $fullpath );
848 if ( !$this->wpmc_trash_file( $file ) ) {
849 $this->log( "Could not trash $file." );
850 error_log( "Media Cleaner: Could not trash $file." );
851 return false;
852 }
853
854 // If images, check the other files as well
855 $meta = wp_get_attachment_metadata( $issue->postId );
856 $isImage = isset( $meta, $meta['width'], $meta['height'] );
857 $sizes = $this->wpmc_get_image_sizes();
858 if ( $isImage && isset( $meta['sizes'] ) ) {
859 foreach ( $meta['sizes'] as $name => $attr ) {
860 if ( isset( $attr['file'] ) ) {
861 $filepath = wp_upload_dir();
862 $filepath = $filepath['basedir'];
863 $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
864 $file = $this->wpmc_clean_uploaded_filename( $filepath );
865 if ( !$this->wpmc_trash_file( $file ) ) {
866 $this->log( "Could not trash $file." );
867 error_log( "Media Cleaner: Could not trash $file." );
868 }
869 }
870 }
871 }
872 wp_delete_attachment( $issue->postId, false );
873 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 1 WHERE id = %d", $id ) );
874 return true;
875 }
876 else {
877 // Trash Media definitely by recovering it (to be like a normal Media) and remove it through the
878 // standard WordPress workflow
879 if ( MEDIA_TRASH )
880 $this->wpmc_recover( $id );
881 wp_delete_attachment( $issue->postId, true );
882 $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE id = %d", $id ) );
883 return true;
884 }
885 }
886 return false;
887 }
888
889 /**
890 *
891 * SCANNING / RESET
892 *
893 */
894
895 function wpmc_check_is_ignore( $file ) {
896 global $wpdb;
897 $table_name = $wpdb->prefix . "wpmcleaner";
898 $count = $wpdb->get_var( "SELECT COUNT(*)
899 FROM $table_name
900 WHERE ignored = 1
901 AND path LIKE '%". esc_sql( $wpdb->esc_like( $file ) ) . "%'" );
902 if ( $count > 0 ) {
903 $this->log( "Could not trash $file." );
904 }
905 return ($count > 0);
906 }
907
908 function wpmc_find_attachment_id_by_file( $file ) {
909 global $wpdb;
910 $postmeta_table_name = $wpdb->prefix . 'postmeta';
911 $file = $this->wpmc_clean_uploaded_filename( $file );
912 $sql = $wpdb->prepare( "SELECT post_id
913 FROM {$postmeta_table_name}
914 WHERE meta_key = '_wp_attached_file'
915 AND meta_value = %s", $file
916 );
917 $ret = $wpdb->get_var( $sql );
918 if ( empty( $ret ) )
919 $this->log( "File $file not found as _wp_attached_file (Library)." );
920 else {
921 $this->log( "File $file found as Media $ret." );
922 }
923 return $ret;
924 }
925
926 function wpmc_get_image_sizes() {
927 $sizes = array();
928 global $_wp_additional_image_sizes;
929 foreach ( get_intermediate_image_sizes() as $s ) {
930 $crop = false;
931 if ( isset( $_wp_additional_image_sizes[$s] ) ) {
932 $width = intval( $_wp_additional_image_sizes[$s]['width'] );
933 $height = intval( $_wp_additional_image_sizes[$s]['height'] );
934 $crop = $_wp_additional_image_sizes[$s]['crop'];
935 } else {
936 $width = get_option( $s.'_size_w' );
937 $height = get_option( $s.'_size_h' );
938 $crop = get_option( $s.'_crop' );
939 }
940 $sizes[$s] = array( 'width' => $width, 'height' => $height, 'crop' => $crop );
941 }
942 return $sizes;
943 }
944
945 function clean_url_from_resolution( $url ) {
946 $pattern = '/[_-]\d+x\d+(?=\.[a-z]{3,4}$)/';
947 $url = preg_replace( $pattern, '', $url );
948 return $url;
949 }
950
951 function clean_url_from_resolution_ref( &$url ) {
952 $url = $this->clean_url_from_resolution( $url );
953 }
954
955 // From a url to the shortened and cleaned url (for example '2013/02/file.png')
956 function wpmc_clean_url( $url ) {
957 $upload_folder = wp_upload_dir();
958 $baseurl = $upload_folder['baseurl'];
959 $baseurl = str_replace( 'https://', 'http://', $baseurl );
960 $baseurl = str_replace( 'http://www.', 'http://', $baseurl );
961 $url = str_replace( 'https://', 'http://', $url );
962 $url = str_replace( 'http://www.', 'http://', $url );
963 $url = str_replace( $baseurl, '', $url );
964 $url = trim( $url, "/" );
965 return $url;
966 }
967
968 // From a fullpath to the shortened and cleaned path (for example '2013/02/file.png')
969 function wpmc_clean_uploaded_filename( $fullpath ) {
970 $upload_folder = wp_upload_dir();
971 $basedir = $upload_folder['basedir'];
972 $file = str_replace( $basedir, '', $fullpath );
973 $file = str_replace( "./", "", $file );
974 $file = trim( $file, "/" );
975 return $file;
976 }
977
978 function wpmc_check_media( $attachmentId, $checkOnly = false ) {
979
980 $this->last_analysis = "N/A";
981
982 // Is it an image?
983 $meta = wp_get_attachment_metadata( $attachmentId );
984 $isImage = isset( $meta, $meta['width'], $meta['height'] );
985
986 // Get the main file
987 global $wpdb;
988 $fullpath = get_attached_file( $attachmentId );
989 $mainfile = $this->wpmc_clean_uploaded_filename( $fullpath );
990 $baseUp = pathinfo( $mainfile );
991 $baseUp = $baseUp['dirname'];
992 $size = 0;
993 $countfiles = 0;
994 $issue = 'NO_CONTENT';
995 if ( file_exists( $fullpath ) ) {
996
997 // Special scan: Broken only!
998 $check_postmeta = get_option( 'wpmc_postmeta', false );
999 $check_posts = get_option( 'wpmc_posts', false );
1000 $check_widgets = get_option( 'wpmc_widgets', false );
1001 if ( !$check_postmeta && !$check_posts && !$check_widgets )
1002 return true;
1003
1004 $size = filesize( $fullpath );
1005
1006 // ANALYSIS
1007 $this->last_analysis = "NONE";
1008 $this->log( "Checking Media #{$attachmentId}: {$mainfile}" );
1009 if ( $this->wpmc_check_is_ignore( $mainfile, $attachmentId ) ) {
1010 $this->last_analysis = "IGNORED";
1011 return true;
1012 }
1013 if ( $this->checkers->has_background_or_header( $mainfile, $attachmentId ) )
1014 return true;
1015 if ( $this->checkers->has_content( $mainfile, $attachmentId ) )
1016 return true;
1017 if ( $this->checkers->check_in_gallery( $mainfile, $attachmentId ) )
1018 return true;
1019 if ( $this->checkers->has_meta( $mainfile, $attachmentId ) )
1020 return true;
1021
1022 // If images, check the other files as well
1023 $countfiles = 0;
1024 $sizes = $this->wpmc_get_image_sizes();
1025 if ( $isImage && isset( $meta['sizes'] ) ) {
1026 foreach ( $meta['sizes'] as $name => $attr ) {
1027 if ( isset( $attr['file'] ) ) {
1028 $filepath = wp_upload_dir();
1029 $filepath = $filepath['basedir'];
1030 $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
1031 if ( file_exists( $filepath ) ) {
1032 $size += filesize( $filepath );
1033 }
1034 $file = $this->wpmc_clean_uploaded_filename( $filepath );
1035 $countfiles++;
1036 $this->log( "Checking Media #{$attachmentId}: {$file}" );
1037
1038 // ANALYSIS
1039 if ( $this->checkers->has_content( $file, $attachmentId ) )
1040 return true;
1041 if ( $this->checkers->check_in_gallery( $file, $attachmentId ) )
1042 return true;
1043 if ( $this->checkers->has_background_or_header( $file, $attachmentId ) )
1044 return true;
1045 if ( $this->checkers->has_meta( $file, $attachmentId ) )
1046 return true;
1047 }
1048 }
1049 }
1050 } else {
1051 $this->log( "File {$fullpath} does not exist." );
1052 $issue = 'ORPHAN_MEDIA';
1053 }
1054
1055 if ( !$checkOnly ) {
1056 $table_name = $wpdb->prefix . "wpmcleaner";
1057 $wpdb->insert( $table_name,
1058 array(
1059 'time' => current_time('mysql'),
1060 'type' => 1,
1061 'size' => $size,
1062 'path' => $mainfile . ( $countfiles > 0 ? ( " (+ " . $countfiles . " files)" ) : "" ),
1063 'postId' => $attachmentId,
1064 'issue' => $issue
1065 )
1066 );
1067 }
1068 return false;
1069 }
1070
1071 // Delete all issues
1072 function wpmc_reset_issues( $includingIgnored = false ) {
1073 global $wpdb;
1074 $table_name = $wpdb->prefix . "wpmcleaner";
1075 if ( $includingIgnored ) {
1076 $wpdb->query( "DELETE FROM $table_name WHERE deleted = 0" );
1077 }
1078 else {
1079 $wpdb->query( "DELETE FROM $table_name WHERE ignored = 0 AND deleted = 0" );
1080 }
1081 if ( file_exists( plugin_dir_path( __FILE__ ) . '/media-cleaner.log' ) ) {
1082 file_put_contents( plugin_dir_path( __FILE__ ) . '/media-cleaner.log', '' );
1083 }
1084 delete_transient( "wpmc_theme_ids" );
1085 delete_transient( "wpmc_theme_urls" );
1086 delete_transient( "wpmc_widgets_ids" );
1087 delete_transient( "wpmc_widgets_urls" );
1088 delete_transient( "wpmc_posts_images_urls" );
1089 delete_transient( "wpmc_posts_images_ids" );
1090 delete_transient( "wpmc_postmeta_images_urls" );
1091 delete_transient( "wpmc_postmeta_images_ids" );
1092 delete_transient( "wpmc_postmeta_images_acf_urls" );
1093 delete_transient( "wpmc_postmeta_images_acf_ids" );
1094 delete_transient( "wpmc_posts_images_visualcomposer" );
1095 delete_transient( "wpmc_galleries_images_visualcomposer" );
1096 delete_transient( "wpmc_galleries_images_fusionbuilder" );
1097 delete_transient( "wpmc_galleries_images_woocommerce" );
1098 delete_transient( "wpmc_galleries_images_divi" );
1099 delete_transient( "wpmc_galleries_images_urls" );
1100 }
1101
1102 /**
1103 *
1104 * DASHBOARD
1105 *
1106 */
1107
1108 function admin_inline_js() {
1109 echo "<script type='text/javascript'>\n";
1110 echo 'var wpmc_cfg = {
1111 delay: ' . get_option( 'wpmc_delay', 100 ) . ',
1112 analysisBuffer: ' . get_option( 'wpmc_analysis_buffer', 50 ) . ',
1113 isPro: ' . ( $this->admin->is_registered() ? '1' : '0') . ',
1114 scanFiles: ' . ( ( get_option( 'wpmc_method', 'media' ) == 'files' && $this->admin->is_registered() ) ? '1' : '0' ) . ',
1115 scanMedia: ' . ( get_option( 'wpmc_method', 'media' ) == 'media' ? '1' : '0' ) . ' };';
1116 echo "\n</script>";
1117 }
1118
1119 function echo_issue( $issue ) {
1120 if ( $issue == 'NO_CONTENT' ) {
1121 _e( "Seems not in use.", 'media-cleaner' );
1122 }
1123 else if ( $issue == 'NO_MEDIA' ) {
1124 _e( "Not in Media Library.", 'media-cleaner' );
1125 }
1126 else if ( $issue == 'ORPHAN_RETINA' ) {
1127 _e( "Orphan retina.", 'media-cleaner' );
1128 }
1129 else if ( $issue == 'ORPHAN_MEDIA' ) {
1130 _e( "File not found.", 'media-cleaner' );
1131 }
1132 else {
1133 echo $issue;
1134 }
1135 }
1136
1137 function media_row_actions( $actions, $post ) {
1138 global $current_screen;
1139 if ( 'upload' != $current_screen->id )
1140 return $actions;
1141 global $wpdb;
1142 $table_name = $wpdb->prefix . "wpmcleaner";
1143 $res = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE postId = %d", $post->ID ) );
1144 if ( !empty( $res ) && isset( $actions['delete'] ) )
1145 $actions['delete'] = "<a href='?page=media-cleaner&view=deleted'>" .
1146 __( 'Delete with Media Cleaner', 'media-cleaner' ) . "</a>";
1147 if ( !empty( $res ) && isset( $actions['trash'] ) )
1148 $actions['trash'] = "<a href='?page=media-cleaner'>" .
1149 __( 'Trash with Media Cleaner', 'media-cleaner' ) . "</a>";
1150 if ( !empty( $res ) && isset( $actions['untrash'] ) ) {
1151 $actions['untrash'] = "<a href='?page=media-cleaner&view=deleted'>" .
1152 __( 'Restore with Media Cleaner', 'media-cleaner' ) . "</a>";
1153 }
1154 return $actions;
1155 }
1156
1157 function wpmc_screen() {
1158 global $wplr;
1159 $this->wpmc_check_db();
1160 ?>
1161 <div class='wrap'>
1162
1163 <?php
1164 echo $this->admin->display_title( "Media Cleaner" );
1165 global $wpdb;
1166 $posts_per_page = get_user_meta( get_current_user_id(), 'upload_per_page', true );
1167 if ( empty( $posts_per_page ) )
1168 $posts_per_page = 20;
1169 $view = isset ( $_GET[ 'view' ] ) ? sanitize_text_field( $_GET[ 'view' ] ) : "issues";
1170 $paged = isset ( $_GET[ 'paged' ] ) ? sanitize_text_field( $_GET[ 'paged' ] ) : 1;
1171 $reset = isset ( $_GET[ 'reset' ] ) ? $_GET[ 'reset' ] : 0;
1172 if ( $reset ) {
1173 wpmc_reset();
1174 $this->wpmc_reset_issues();
1175 }
1176 $s = isset ( $_GET[ 's' ] ) ? sanitize_text_field( $_GET[ 's' ] ) : null;
1177 $table_name = $wpdb->prefix . "wpmcleaner";
1178 $issues_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
1179 $total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
1180 $trash_total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 1" );
1181 $ignored_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE ignored = 1" );
1182 $deleted_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE deleted = 1" );
1183
1184 if ( $view == 'deleted' ) {
1185 $items_count = $deleted_count;
1186 $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
1187 FROM $table_name WHERE ignored = 0 AND deleted = 1 AND path LIKE %s
1188 ORDER BY time
1189 DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
1190 }
1191 else if ( $view == 'ignored' ) {
1192 $items_count = $ignored_count;
1193 $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
1194 FROM $table_name
1195 WHERE ignored = 1 AND deleted = 0 AND path LIKE %s
1196 ORDER BY time
1197 DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
1198 }
1199 else {
1200 $items_count = $issues_count;
1201 $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
1202 FROM $table_name
1203 WHERE ignored = 0 AND deleted = 0 AND path LIKE %s
1204 ORDER BY time
1205 DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
1206 }
1207 ?>
1208
1209 <style>
1210 #wpmc-pages {
1211 float: right;
1212 position: relative;
1213 top: 12px;
1214 }
1215
1216 #wpmc-pages a {
1217 text-decoration: none;
1218 border: 1px solid black;
1219 padding: 2px 5px;
1220 border-radius: 4px;
1221 background: #E9E9E9;
1222 color: lightslategrey;
1223 border-color: #BEBEBE;
1224 }
1225
1226 #wpmc-pages .current {
1227 font-weight: bold;
1228 }
1229 </style>
1230
1231 <div style='margin-top: 0px; background: #FFF; padding: 5px; border-radius: 4px; height: 28px; box-shadow: 0px 0px 6px #C2C2C2;'>
1232
1233 <!-- SCAN -->
1234 <?php if ( $view != 'deleted' ) { ?>
1235 <a id='wpmc_scan' onclick='wpmc_scan()' class='button-primary' style='float: left;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-search"></span><?php _e("Start Scan", 'media-cleaner'); ?></a>
1236 <?php } ?>
1237
1238 <!-- PAUSE -->
1239 <?php if ( $view != 'deleted' ) { ?>
1240 <a id='wpmc_pause' onclick='wpmc_pause()' class='button' style='float: left; margin-left: 5px; display: none;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-controls-pause"></span><?php _e("Pause", 'media-cleaner'); ?></a>
1241 <?php } ?>
1242
1243 <!-- DELETE SELECTED -->
1244 <a id='wpmc_delete' onclick='wpmc_delete()' class='button' style='float: left; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-no"></span><?php _e("Delete", 'media-cleaner'); ?></a>
1245 <?php if ( $view == 'deleted' ) { ?>
1246 <a id='wpmc_recover' onclick='wpmc_recover()' class='button-secondary' style='float: left; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-controls-repeat"></span><?php _e( "Recover", 'media-cleaner' ); ?></a>
1247 <?php } ?>
1248
1249 <!-- IGNORE SELECTED -->
1250 <a id='wpmc_ignore' onclick='wpmc_ignore()' class='button' style='float: left; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-yes"></span><?php
1251 if ( $view == 'ignored' )
1252 _e( "Mark as Issue", 'media-cleaner' );
1253 else
1254 _e( "Ignore", 'media-cleaner' );
1255 ?>
1256 </a>
1257
1258 <!-- RESET -->
1259 <?php if ( $view != 'deleted' ) { ?>
1260 <a id='wpmc_reset' href='?page=media-cleaner&reset=1' class='button-primary' style='float: right; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-sos"></span><?php _e("Reset", 'media-cleaner'); ?></a>
1261 <?php } ?>
1262
1263 <!-- DELETE ALL -->
1264 <?php if ( $view == 'deleted' ) { ?>
1265 <a id='wpmc_recover_all' onclick='wpmc_recover_all()' class='button-primary' style='float: right; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-controls-repeat"></span><?php _e("Recover all", 'media-cleaner'); ?></a>
1266 <a id='wpmc_delete_all' onclick='wpmc_delete_all(true)' class='button button-red' style='float: right; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-trash"></span><?php _e("Empty trash", 'media-cleaner'); ?></a>
1267 <?php } else { ?>
1268 <a id='wpmc_delete_all' onclick='wpmc_delete_all()' class='button button-red' style='float: right; margin-left: 5px;'><span style="top: 3px; position: relative; left: -5px;" class="dashicons dashicons-trash"></span><?php _e("Delete all", 'media-cleaner'); ?></a>
1269 <?php } ?>
1270
1271 <form id="posts-filter" action="upload.php" method="get" style='float: right;'>
1272 <p class="search-box" style='margin-left: 5px; float: left;'>
1273 <input type="search" name="s" style="width: 120px;" value="<?php echo $s ? $s : ""; ?>">
1274 <input type="hidden" name="page" value="media-cleaner">
1275 <input type="hidden" name="view" value="<?php echo $view; ?>">
1276 <input type="hidden" name="paged" value="1">
1277 <input type="submit" class="button" value="<?php _e( 'Search', 'media-cleaner' ) ?>"><span style='border-right: #A2A2A2 solid 1px; margin-left: 5px; margin-right: 3px;'>&nbsp;</span>
1278 </p>
1279 </form>
1280
1281 <!-- PROGRESS -->
1282 <span style='margin-left: 12px; font-size: 15px; top: 5px; position: relative; color: #747474;' id='wpmc_progression'></span>
1283
1284 </div>
1285
1286 <p>
1287 <?php
1288 $method = get_option( 'wpmc_method', 'media' );
1289 if ( !$this->admin->is_registered() )
1290 $method = 'media';
1291
1292 $hide_warning = get_option( 'wpmc_hide_warning', false );
1293
1294 if ( !$hide_warning ) {
1295 _e( "<div class='notice notice-error'><p><b style='color: red;'>Important.</b> <b>Backup your DB and your /uploads directory before using Media Cleaner. </b> The deleted files will be temporarily moved to the <b>uploads/wpmc-trash</b> directory. After testing your website, you can check the <a href='?page=media-cleaner&s&view=deleted'>trash</a> to either empty it or recover the media and files. The Media Cleaner does its best to be safe to use. However, WordPress being a very dynamic and pluggable system, it is impossible to predict all the situations in which your files are used. <b style='color: red;'>Again, please backup!</b> If you don't know how, give a try to this: <a href='https://updraftplus.com/?afref=460' target='_blank'>UpdraftPlus</a>. <br /><br /><b style='color: red;'>Be thoughtful.</b> Don't blame Media Cleaner if it deleted too many or not enough of your files. It makes cleaning possible and this task is only possible this way; don't post a bad review because it broke your install. <b>If you have a proper backup, there is no risk</b>. Sorry for the lengthy message, but better be safe than sorry. You can disable this big warning in the options if you have a Pro license. Make sure you read this warning twice. Media Cleaner is awesome and always getting better so I hope you will enjoy it. Thank you :)</p></div>", 'media-cleaner' );
1296 }
1297
1298 if ( !MEDIA_TRASH ) {
1299 _e( "<div class='notice notice-warning'><p>The trash for the Media Library is disabled. Any media removed by the plugin will be <b>permanently deleted</b>. To enable it, modify your wp-config.php file and add this line (preferably at the top):<br /><b>define( 'MEDIA_TRASH', true );</b></p></div>", 'media-cleaner' );
1300 }
1301
1302 if ( !$this->admin->is_registered() ) {
1303 echo "<div class='notice notice-info'><p>";
1304 _e( "<b>This version is not Pro.</b> This plugin is a lot of work so please consider <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a> in order to receive support and to contribute in the evolution of it. Also, <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a> version will also give you the option <b>to scan the physical files in your /uploads folder</b> and extra checks for the common Page Builders.", 'media-cleaner' );
1305 echo "</p></div>";
1306
1307 if ( function_exists( '_et_core_find_latest' ) ) {
1308 echo "<div class='notice notice-warning'><p>";
1309 _e( "<b>Divi has been detected</b>. The free version might detect the files used by Divi correctly, but its full support is only available in <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a>.", 'media-cleaner' );
1310 echo "</p></div>";
1311 }
1312
1313 if ( class_exists( 'Vc_Manager' ) ) {
1314 echo "<div class='notice notice-warning'><p>";
1315 _e( "<b>Visual Composer has been detected</b>. The free version might detect the files used by Visual Composer correctly, but its full support is only available in <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a>.", 'media-cleaner' );
1316 echo "</p></div>";
1317 }
1318
1319 if ( function_exists( 'fusion_builder_map' ) ) {
1320 echo "<div class='notice notice-warning'><p>";
1321 _e( "<b>Fusion Builder has been detected</b>. The free version might detect the files used by Fusion Builder correctly, but its full support is only available in <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a>.", 'media-cleaner' );
1322 echo "</p></div>";
1323 }
1324
1325 if ( class_exists( 'FLBuilderModel' ) ) {
1326 echo "<div class='notice notice-warning'><p>";
1327 _e( "<b>Beaver Builder has been detected</b>. The free version might detect the files used by Beaver Builder correctly, but its full support is only available in <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a>.", 'media-cleaner' );
1328 echo "</p></div>";
1329 }
1330
1331 if ( function_exists( 'elementor_load_plugin_textdomain' ) ) {
1332 echo "<div class='notice notice-warning'><p>";
1333 _e( "<b>Elementor has been detected</b>. The free version might detect the files used by Elementor correctly, but its full support is only available in <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a>.", 'media-cleaner' );
1334 echo "</p></div>";
1335 }
1336
1337 if ( class_exists( 'SiteOrigin_Panels' ) ) {
1338 echo "<div class='notice notice-warning'><p>";
1339 _e( "<b>SiteOrigin Page Builder has been detected</b>. The free version might detect the files used by SiteOrigin Page Builder correctly, but its full support is only available in <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a>.", 'media-cleaner' );
1340 echo "</p></div>";
1341 }
1342
1343 }
1344
1345 $anychecks = get_option( 'wpmc_posts', false ) || get_option( 'wpmc_postmeta', false ) || get_option( 'wpmc_widgets', false );
1346 $check_library = get_option(' wpmc_media_library', true );
1347
1348 if ( $method == 'media' ) {
1349 if ( !$anychecks )
1350 _e( "<div class='error'><p>Media Cleaner will analyze your Media Library. However, There is <b>NOTHING MARKED TO BE CHECKED</b> in the Settings. Media Cleaner will therefore run a special scan: <b>only the broken medias will be detected as issues.</b></p></div>", 'media-cleaner' );
1351 else
1352 _e( "<div class='notice notice-success'><p>Media Cleaner will analyze your Media Library.</p></div>", 'media-cleaner' );
1353 }
1354 else if ( $method == 'files' ) {
1355 if ( !$anychecks && !$check_library )
1356 _e( "<div class='error'><p>Media Cleaner will analyze your Filesystem. However, There is <b>NOTHING MARKED TO BE CHECKED</b> in the Settings. If you scan now, all the files will be detected as <b>NOT USED</b>.</p></div>", 'media-cleaner' );
1357 else
1358 _e( "<div class='notice notice-success'><p>Media Cleaner will analyze your Filesystem.</p></div>", 'media-cleaner' );
1359 }
1360
1361 echo sprintf( __( 'There are <b>%s issue(s)</b> with your files, accounting for <b>%s MB</b>. Your trash contains <b>%s MB.</b>', 'media-cleaner' ), number_format( $issues_count, 0 ), number_format( $total_size / 1000000, 2 ), number_format( $trash_total_size / 1000000, 2 ) );
1362 ?>
1363 </p>
1364
1365 <div id='wpmc-pages'>
1366 <?php
1367 echo paginate_links(array(
1368 'base' => '?page=media-cleaner&s=' . urlencode($s) . '&view=' . $view . '%_%',
1369 'current' => $paged,
1370 'format' => '&paged=%#%',
1371 'total' => ceil( $items_count / $posts_per_page ),
1372 'prev_next' => false
1373 ));
1374 ?>
1375 </div>
1376
1377 <ul class="subsubsub">
1378 <li class="all"><a <?php if ( $view == 'issues' ) echo "class='current'"; ?> href='?page=media-cleaner&s=<?php echo $s; ?>&view=issues'><?php _e( "Issues", 'media-cleaner' ); ?></a><span class="count">(<?php echo $issues_count; ?>)</span></li> |
1379 <li class="all"><a <?php if ( $view == 'ignored' ) echo "class='current'"; ?> href='?page=media-cleaner&s=<?php echo $s; ?>&view=ignored'><?php _e( "Ignored", 'media-cleaner' ); ?></a><span class="count">(<?php echo $ignored_count; ?>)</span></li> |
1380 <li class="all"><a <?php if ( $view == 'deleted' ) echo "class='current'"; ?> href='?page=media-cleaner&s=<?php echo $s; ?>&view=deleted'><?php _e( "Trash", 'media-cleaner' ); ?></a><span class="count">(<?php echo $deleted_count; ?>)</span></li>
1381 </ul>
1382
1383 <table id='wpmc-table' class='wp-list-table widefat fixed media'>
1384
1385 <thead>
1386 <tr>
1387 <th scope="col" id="cb" class="manage-column column-cb check-column"><input id="wpmc-cb-select-all" type="checkbox"></th>
1388 <?php if ( !get_option( 'wpmc_hide_thumbnails', false ) ): ?>
1389 <th style='width: 64px;'><?php _e( 'Thumb', 'media-cleaner' ) ?></th>
1390 <?php endif; ?>
1391 <th style='width: 50px;'><?php _e( 'Type', 'media-cleaner' ) ?></th>
1392 <th style='width: 80px;'><?php _e( 'Origin', 'media-cleaner' ) ?></th>
1393
1394 <?php if ( !empty( $wplr ) ): ?>
1395 <th style='width: 70px;'><?php _e( 'LR ID', 'media-cleaner' ) ?></th>
1396 <?php endif; ?>
1397
1398 <th><?php _e( 'Path', 'media-cleaner' ) ?></th>
1399 <th style='width: 220px;'><?php _e( 'Issue', 'media-cleaner' ) ?></th>
1400 <th style='width: 80px; text-align: right;'><?php _e( 'Size', 'media-cleaner' ) ?></th>
1401 </tr>
1402 </thead>
1403
1404 <tbody>
1405 <?php
1406 foreach ( $items as $issue ) {
1407 $regex = "^(.*)(\\s\\(\\+.*)$";
1408 $issue->path = preg_replace( '/' .$regex . '/i', '$1', $issue->path );
1409 ?>
1410 <tr>
1411 <td><input type="checkbox" name="id" value="<?php echo $issue->id ?>"></td>
1412 <?php if ( !get_option( 'wpmc_hide_thumbnails', false ) ): ?>
1413 <td>
1414 <?php
1415 if ( $issue->deleted == 0 ) {
1416 if ( $issue ->type == 0 ) {
1417 // FILE
1418 $upload_dir = wp_upload_dir();
1419 $url = htmlspecialchars( $upload_dir['baseurl'] . '/' . $issue->path, ENT_QUOTES );
1420 echo "<a target='_blank' href='" . $url .
1421 "'><img style='max-width: 48px; max-height: 48px;' src='" . $url . "' /></a>";
1422 }
1423 else {
1424 // MEDIA
1425 $file = get_attached_file( $issue->postId );
1426 if ( file_exists( $file ) ) {
1427 $attachmentsrc = wp_get_attachment_image_src( $issue->postId, 'thumbnail' );
1428 if ( empty( $attachmentsrc ) )
1429 echo '<span class="dashicons dashicons-no-alt"></span>';
1430 else {
1431 $attachmentsrc_clean = htmlspecialchars( $attachmentsrc[0], ENT_QUOTES );
1432 echo "<a target='_blank' href='" . $attachmentsrc_clean .
1433 "'><img style='max-width: 48px; max-height: 48px;' src='" .
1434 $attachmentsrc_clean . "' />";
1435 }
1436 }
1437 else {
1438 echo '<span class="dashicons dashicons-no-alt"></span>';
1439 }
1440 }
1441 }
1442 if ( $issue->deleted == 1 ) {
1443 $upload_dir = wp_upload_dir();
1444 $url = htmlspecialchars( $upload_dir['baseurl'] . '/wpmc-trash/' . $issue->path, ENT_QUOTES );
1445 echo "<a target='_blank' href='" . $url .
1446 "'><img style='max-width: 48px; max-height: 48px;' src='" . $url . "' /></a>";
1447 }
1448 ?>
1449 </td>
1450 <?php endif; ?>
1451 <td><?php echo $issue->type == 0 ? 'FILE' : 'MEDIA'; ?></td>
1452 <td><?php echo $issue->type == 0 ? 'Filesystem' : ("<a href='post.php?post=" .
1453 $issue->postId . "&action=edit'>ID " . $issue->postId . "</a>"); ?></td>
1454 <?php if ( !empty( $wplr ) ) { $info = $wplr->get_sync_info( $issue->postId ); ?>
1455 <td style='width: 70px;'><?php echo ( !empty( $info ) && $info->lr_id ? $info->lr_id : "" ); ?></td>
1456 <?php } ?>
1457 <td><?php echo stripslashes( $issue->path ); ?></td>
1458 <td><?php $this->echo_issue( $issue->issue ); ?></td>
1459 <td style='text-align: right;'><?php echo number_format( $issue->size / 1000, 2 ); ?> KB</td>
1460 </tr>
1461 <?php } ?>
1462 </tbody>
1463
1464 <tfoot>
1465 <tr><th></th>
1466 <?php if ( !get_option( 'hide_thumbnails', false ) ): ?>
1467 <th></th>
1468 <?php endif; ?>
1469 <th><?php _e( 'Type', 'media-cleaner' ) ?></th><th><?php _e( 'Origin', 'media-cleaner' ) ?></th>
1470 <?php if ( !empty( $wplr ) ): ?>
1471 <th style='width: 70px;'><?php _e( 'LR ID', 'media-cleaner' ) ?></th>
1472 <?php endif; ?>
1473 <th><?php _e( 'Path', 'media-cleaner' ) ?></th><th><?php _e( 'Issue', 'media-cleaner' ) ?></th><th style='width: 80px; text-align: right;'><?php _e( 'Size', 'media-cleaner' ) ?></th></tr>
1474 </tfoot>
1475
1476 </table>
1477 </wrap>
1478
1479 <?php
1480 }
1481
1482 function admin_menu() {
1483 //load_plugin_textdomain( 'media-cleaner', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
1484 add_media_page( 'Media Cleaner', 'Cleaner', 'manage_options', 'media-cleaner', array( $this, 'wpmc_screen' ) );
1485 }
1486
1487 function wp_enqueue_scripts () {
1488 wp_enqueue_style( 'media-cleaner-css', plugins_url( '/media-cleaner.css', __FILE__ ) );
1489 wp_enqueue_script( 'media-cleaner', plugins_url( '/media-cleaner.js', __FILE__ ), array( 'jquery' ), "3.7.0", true );
1490 }
1491 }
1492
1493
1494 /*
1495 INSTALL / UNINSTALL
1496 */
1497
1498 register_activation_hook( __FILE__, 'wpmc_activate' );
1499 register_deactivation_hook( __FILE__, 'wpmc_uninstall' );
1500 register_uninstall_hook( __FILE__, 'wpmc_uninstall' );
1501
1502 function wpmc_reset() {
1503 wpmc_uninstall();
1504 wpmc_activate();
1505 }
1506
1507 function wpmc_activate () {
1508 global $wpdb;
1509 $table_name = $wpdb->prefix . "wpmcleaner";
1510 $charset_collate = $wpdb->get_charset_collate();
1511 $sql = "CREATE TABLE $table_name (
1512 id BIGINT(20) NOT NULL AUTO_INCREMENT,
1513 time DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL,
1514 type TINYINT(1) NOT NULL,
1515 postId BIGINT(20) NULL,
1516 path TINYTEXT NULL,
1517 size INT(9) NULL,
1518 ignored TINYINT(1) NOT NULL DEFAULT 0,
1519 deleted TINYINT(1) NOT NULL DEFAULT 0,
1520 issue TINYTEXT NOT NULL,
1521 UNIQUE KEY id (id)
1522 ) " . $charset_collate . ";";
1523 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
1524 dbDelta( $sql );
1525
1526 $upload_folder = wp_upload_dir();
1527 $basedir = $upload_folder['basedir'];
1528 if ( !is_writable( $basedir ) ) {
1529 echo '<div class="error"><p>' . __( 'The directory for uploads is not writable. Media Cleaner will only be able to scan.', 'media-cleaner' ) . '</p></div>';
1530 }
1531 }
1532
1533 function wpmc_uninstall () {
1534 global $wpdb;
1535 $table_name = $wpdb->prefix . "wpmcleaner";
1536 $wpdb->query("DROP TABLE IF EXISTS $table_name");
1537 }
1538