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