PluginProbe ʕ •ᴥ•ʔ
Media Cleaner: Clean your WordPress! / 4.2.0
Media Cleaner: Clean your WordPress! v4.2.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
1294 lines
1 <?php
2
3 class Meow_WPMC_Core {
4
5 public $checkers = null;
6 public $admin = null;
7
8 public $last_analysis = null;
9 public $last_analysis_ids = null;
10
11 public function __construct( $admin ) {
12 $this->admin = $admin;
13 add_action( 'admin_menu', array( $this, 'admin_menu' ) );
14 add_action( 'admin_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ) );
15 add_action( 'admin_print_scripts', array( $this, 'admin_inline_js' ) );
16 add_action( 'wp_ajax_wpmc_scan', array( $this, 'wp_ajax_wpmc_scan' ) );
17 add_action( 'wp_ajax_wpmc_get_all_issues', array( $this, 'wp_ajax_wpmc_get_all_issues' ) );
18 add_action( 'wp_ajax_wpmc_get_all_deleted', array( $this, 'wp_ajax_wpmc_get_all_deleted' ) );
19 add_action( 'wp_ajax_wpmc_scan_do', array( $this, 'wp_ajax_wpmc_scan_do' ) );
20 add_action( 'wp_ajax_wpmc_prepare_do', array( $this, 'wp_ajax_wpmc_prepare_do' ) );
21 add_action( 'wp_ajax_wpmc_delete_do', array( $this, 'wp_ajax_wpmc_delete_do' ) );
22 add_action( 'wp_ajax_wpmc_ignore_do', array( $this, 'wp_ajax_wpmc_ignore_do' ) );
23 add_action( 'wp_ajax_wpmc_recover_do', array( $this, 'wp_ajax_wpmc_recover_do' ) );
24 add_filter( 'media_row_actions', array( $this, 'media_row_actions' ), 10, 2 );
25
26 if ( is_admin() ) {
27 add_action( 'add_meta_boxes', array( $this, 'add_metabox' ) );
28 }
29
30 // Checkers
31 require( 'wpmc_checkers.php' );
32 $this->checkers = new Meow_WPMC_Checkers( $this );
33 }
34
35 /*******************************************************************************
36 * METABOX FOR USAGE
37 ******************************************************************************/
38
39 function add_metabox() {
40 add_meta_box( 'mfrh_media_usage_box', 'Media Cleaner', array( $this, 'display_metabox' ), 'attachment', 'side', 'default' );
41 }
42
43 function display_metabox( $post ) {
44 $posts_images_urls = get_transient( "wpmc_posts_images_urls" );
45 if ( !is_array( $posts_images_urls ) ) {
46 echo "You need to run a scan first.";
47 return;
48 }
49 $this->log( "Media Edit > Checking Media #{$post->ID}" );
50 $success = $this->wpmc_check_media( $post->ID );
51 $this->log( "Success " . $success . "\n" );
52 if ( $success ) {
53 if ( $this->last_analysis == "CONTENT" ) {
54 echo "Found in the content.";
55 }
56 else if ( $this->last_analysis == "THEME" ) {
57 echo "Found in the theme.";
58 }
59 else if ( $this->last_analysis == "GALLERY" ) {
60 echo "Found in a gallery.";
61 }
62 else if ( $this->last_analysis == "META" ) {
63 echo "Found in meta.";
64 }
65 else if ( $this->last_analysis == "WIDGET" ) {
66 echo "Found in widget.";
67 }
68 else {
69 echo "Used: " . $this->last_analysis;
70 }
71 }
72 else {
73 echo "Doesn't seem to be used.";
74 }
75 }
76
77 /*******************************************************************************
78 * ASYNCHRONOUS AJAX FUNCTIONS
79 ******************************************************************************/
80
81 function wp_ajax_wpmc_delete_do () {
82 ob_start();
83 $data = $_POST['data'];
84 $success = 0;
85 foreach ( $data as $piece ) {
86 $success += ( $this->wpmc_delete( $piece ) ? 1 : 0 );
87 }
88 ob_end_clean();
89 echo json_encode(
90 array(
91 'success' => true,
92 'result' => array( 'data' => $data, 'success' => $success ),
93 'message' => __( "Status unknown.", 'media-cleaner' )
94 )
95 );
96 die();
97 }
98
99 function wp_ajax_wpmc_ignore_do () {
100 ob_start();
101 $data = $_POST['data'];
102 $success = 0;
103 foreach ( $data as $piece ) {
104 $success += ( $this->wpmc_ignore( $piece ) ? 1 : 0 );
105 }
106 ob_end_clean();
107 echo json_encode(
108 array(
109 'success' => true,
110 'result' => array( 'data' => $data, 'success' => $success ),
111 'message' => __( "Status unknown.", 'media-cleaner' )
112 )
113 );
114 die();
115 }
116
117 function wp_ajax_wpmc_recover_do () {
118 ob_start();
119 $data = $_POST['data'];
120 $success = 0;
121 foreach ( $data as $piece ) {
122 $success += ( $this->wpmc_recover( $piece ) ? 1 : 0 );
123 }
124 ob_end_clean();
125 echo json_encode(
126 array(
127 'success' => true,
128 'result' => array( 'data' => $data, 'success' => $success ),
129 'message' => __( "Status unknown.", 'media-cleaner' )
130 )
131 );
132 die();
133 }
134
135 function wp_ajax_wpmc_scan_do () {
136 // For debug, to pretend there is a timeout
137 // header("HTTP/1.0 408 Request Timeout");
138 // exit;
139 ob_start();
140 $type = $_POST['type'];
141 $data = $_POST['data'];
142 $success = 0;
143 foreach ( $data as $piece ) {
144 if ( $type == 'file' ) {
145 $this->log( "Check File: {$piece}" );
146 $success += ( apply_filters( 'wpmc_check_file', true, $piece ) ? 1 : 0 );
147 $this->log( "Success " . $success . "\n" );
148 } elseif ( $type == 'media' ) {
149 $this->log( "Checking Media #{$piece}" );
150 $success += ( $this->wpmc_check_media( $piece ) ? 1 : 0 );
151 $this->log( "Success " . $success . "\n" );
152 }
153 }
154 ob_end_clean();
155 echo json_encode(
156 array(
157 'success' => true,
158 'result' => array( 'type' => $type, 'data' => $data, 'success' => $success ),
159 'message' => __( "Items checked.", 'media-cleaner' )
160 )
161 );
162 die();
163 }
164
165 function wp_ajax_wpmc_get_all_deleted () {
166 global $wpdb;
167 $table_name = $wpdb->prefix . "wpmcleaner";
168 $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 1" );
169 echo json_encode(
170 array(
171 'results' => array( 'ids' => $ids ),
172 'success' => true,
173 'message' => __( "List generated.", 'media-cleaner' )
174 )
175 );
176 die;
177 }
178
179 function wp_ajax_wpmc_get_all_issues () {
180 global $wpdb;
181 $isTrash = ( isset( $_POST['isTrash'] ) && $_POST['isTrash'] == 1 ) ? true : false;
182 $table_name = $wpdb->prefix . "wpmcleaner";
183 if ( $isTrash )
184 $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 1" );
185 else
186 $ids = $wpdb->get_col( "SELECT id FROM $table_name WHERE ignored = 0 AND deleted = 0" );
187 echo json_encode(
188 array(
189 'results' => array( 'ids' => $ids ),
190 'success' => true,
191 'message' => __( "List generated.", 'media-cleaner' )
192 )
193 );
194 die;
195 }
196
197 function wp_ajax_wpmc_prepare_do() {
198 $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
199 $limitsize = get_option( 'wpmc_posts_buffer', 10 );
200 if ( empty( $limit ) )
201 $this->wpmc_reset_issues();
202 $check_posts = get_option( 'wpmc_posts', false );
203 $check_galleries = get_option( 'wpmc_galleries', false );
204 if ( !$check_galleries && !$check_posts ) {
205 echo json_encode( array(
206 'results' => array(),
207 'success' => true,
208 'finished' => true,
209 'message' => __( "Galleries and Posts analysis is off. Done.", 'media-cleaner' )
210 ) );
211 die();
212 }
213
214 global $wpdb;
215 $posts = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
216 WHERE p.post_status != 'inherit'
217 AND p.post_status != 'trash'
218 AND p.post_type != 'attachment'
219 AND p.post_type != 'revision'
220 LIMIT %d, %d", $limit, $limitsize
221 )
222 );
223
224 $found = array();
225 $shortcode_support = get_option( 'wpmc_shortcode', false );
226
227 // Analyze Widgets
228 if ( get_option( 'wpmc_widgets', false ) && empty( $limit ) ) {
229 $widgets_content = "";
230 global $wp_registered_widgets;
231 $syswidgets = $wp_registered_widgets;
232 $active_widgets = get_option( 'sidebars_widgets' );
233 // Contatenation of the widgets
234 foreach ( $active_widgets as $sidebar_name => $widgets ) {
235 if ( $sidebar_name != 'wp_inactive_widgets' && !empty( $widgets ) && is_array( $widgets ) ) {
236 $i = 0;
237 foreach ( $widgets as $widget ) {
238 $widget_class = $syswidgets[$widget]['callback'][0]->option_name;
239 $instance_id = $syswidgets[$widget]['params'][0]['number'];
240 $widget_data = get_option($widget_class);
241 if ( !empty( $widget_data[$instance_id]['text'] ) ) {
242 if ( $shortcode_support )
243 $widgets_content .= do_shortcode( $widget_data[$instance_id]['text'] );
244 else
245 $widgets_content .= $widget_data[$instance_id]['text'];
246 }
247 $i++;
248 }
249 }
250 }
251 $widgets_images = array();
252 preg_match_all( "/https?:\/\/[^\/\s]+\/\S+\.(jpg|png|gif)/", $widgets_content, $res );
253 if ( !empty( $res ) && isset( $res[0] ) && count( $res[0] ) > 0 ) {
254 array_walk( $res[0], array( $this, "wpmc_clean_url_direct" ) );
255 $widgets_images = array_merge( $widgets_images, $res[0] );
256 }
257 set_transient( "wpmc_widgets_images", $widgets_images, 60 * 60 * 2 );
258 $found['wpmc_widgets_images'] = $widgets_images;
259
260
261 }
262
263 // Analyze Posts
264 foreach ( $posts as $post ) {
265
266 $html = get_post_field( 'post_content', $post );
267
268 if ( $check_posts ) {
269
270 // Single Image in Visual Composer (WPBakery)
271 if ( class_exists( 'Vc_Manager' ) ) {
272 $posts_images_vc = get_transient( "wpmc_posts_images_visualcomposer" );
273 if ( empty( $posts_images_vc ) )
274 $posts_images_vc = array();
275 preg_match_all( "/image=\"([0-9]+)\"/", $html, $res );
276 if ( !empty( $res ) && isset( $res[1] ) && count( $res[1] ) > 0 ) {
277 $posts_images_vc = array_merge( $posts_images_vc, $res[1] );
278 }
279 set_transient( "wpmc_posts_images_visualcomposer", $posts_images_vc, 60 * 60 * 2 );
280 $found['wpmc_posts_images_visualcomposer'] = $posts_images_vc;
281 }
282
283 // Let's resolve the shortcodes if the option is on
284 if ( $shortcode_support )
285 $html = do_shortcode( $html );
286
287 // Check for images urls in posts
288 $posts_images_urls = get_transient( "wpmc_posts_images_urls" );
289 if ( empty( $posts_images_urls ) )
290 $posts_images_urls = array();
291 preg_match_all( "/https?:\/\/[^\/\s]+\/\S+\.(jpg|png|gif)/", $html, $res );
292 if ( !empty( $res ) && isset( $res[0] ) && count( $res[0] ) > 0 ) {
293 array_walk( $res[0], array( $this, "wpmc_clean_url_direct" ) );
294 $posts_images_urls = array_merge( $posts_images_urls, $res[0] );
295 }
296 set_transient( "wpmc_posts_images_urls", $posts_images_urls, 60 * 60 * 2 );
297 $found['wpmc_posts_images_urls'] = $posts_images_urls;
298
299 // Check for images IDs through classes in in posts
300 $posts_images_ids = get_transient( "wpmc_posts_images_ids" );
301 if ( empty( $posts_images_ids ) )
302 $posts_images_ids = array();
303 preg_match_all( "/wp-image-([0-9]+)/", $html, $res );
304 if ( !empty( $res ) && isset( $res[1] ) && count( $res[1] ) > 0 )
305 $posts_images_ids = array_merge( $posts_images_ids, $res[1] );
306 set_transient( "wpmc_posts_images_ids", $posts_images_ids, 60 * 60 * 2 );
307 $found['wpmc_posts_images_ids'] = $posts_images_ids;
308 }
309
310 if ( $check_galleries ) {
311
312 // Galleries in Visual Composer (WPBakery)
313 if ( class_exists( 'Vc_Manager' ) ) {
314 $galleries_images_vc = get_transient( "wpmc_galleries_images_visualcomposer" );
315 if ( empty( $galleries_images_vc ) )
316 $galleries_images_vc = array();
317 preg_match_all( "/images=\"([0-9,]+)/", $html, $res );
318 if ( !empty( $res ) && isset( $res[1] ) ) {
319 foreach ( $res[1] as $r ) {
320 $ids = explode( ',', $r );
321 $galleries_images_vc = array_merge( $galleries_images_vc, $ids );
322 }
323 }
324 set_transient( "wpmc_galleries_images_visualcomposer", $galleries_images_vc, 60 * 60 * 2 );
325 $found['wpmc_galleries_images_visualcomposer'] = $galleries_images_vc;
326 }
327
328 // Galleries in Fusion Builder (Avada Theme)
329 if ( function_exists( 'fusion_builder_map' ) ) {
330 $galleries_images_fb = get_transient( "wpmc_galleries_images_fusionbuilder" );
331 if ( empty( $galleries_images_fb ) )
332 $galleries_images_fb = array();
333 preg_match_all( "/image_ids=\"([0-9,]+)/", $html, $res );
334 if ( !empty( $res ) && isset( $res[1] ) ) {
335 foreach ( $res[1] as $r ) {
336 $ids = explode( ',', $r );
337 $galleries_images_fb = array_merge( $galleries_images_fb, $ids );
338 }
339 }
340 set_transient( "wpmc_galleries_images_fusionbuilder", $galleries_images_fb, 60 * 60 * 2 );
341 $found['wpmc_galleries_images_fusionbuilder'] = $galleries_images_fb;
342 }
343
344 // WooCommerce
345 if ( class_exists( 'WooCommerce' ) ) {
346 $galleries_images_wc = get_transient( "wpmc_galleries_images_woocommerce" );
347 if ( empty( $galleries_images_wc ) )
348 $galleries_images_wc = array();
349 $res = $wpdb->get_col( "SELECT maeta_value FROM $wpdb->postmeta WHERE post_id = $post
350 AND meta_key = '_product_image_gallery'" );
351 foreach ( $res as $values ) {
352 $ids = explode( ',', $values );
353 $galleries_images_wc = array_merge( $galleries_images_wc, $ids );
354 }
355 set_transient( "wpmc_galleries_images_woocommerce", $galleries_images_wc, 60 * 60 * 2 );
356 $found['wpmc_galleries_images_woocommerce'] = $galleries_images_wc;
357 }
358
359 // Standard WP Gallery
360 $galleries_images = get_transient( "wpmc_galleries_images" );
361 if ( empty( $galleries_images ) )
362 $galleries_images = array();
363 $galleries = get_post_galleries_images( $post );
364 foreach ( $galleries as $gallery ) {
365 foreach ( $gallery as $image ) {
366 array_push( $galleries_images, $this->wpmc_clean_url( $image ) );
367 }
368 }
369 set_transient( "wpmc_galleries_images", $galleries_images, 60 * 60 * 2 );
370 $found['wpmc_galleries_images'] = $galleries_images;
371 }
372 }
373 $finished = count( $posts ) < $limitsize;
374 if ( $finished ) {
375 $found = array();
376 $posts_images_urls = get_transient( "wpmc_posts_images_urls" );
377 $posts_images_ids = get_transient( "wpmc_posts_images_ids" );
378 $posts_images_vc = get_transient( "wpmc_posts_images_visualcomposer" );
379 $galleries_images = get_transient( "wpmc_galleries_images" );
380 $galleries_images_vc = get_transient( "wpmc_galleries_images_visualcomposer" );
381 $galleries_images_fb = get_transient( "wpmc_galleries_images_fusionbuilder" );
382 $galleries_images_wc = get_transient( "wpmc_galleries_images_woocommerce" );
383 $widgets_images = get_transient( "wpmc_widgets_images" );
384 $found['posts_images_urls'] = is_array( $posts_images_urls ) ? array_unique( $posts_images_urls ) : array();
385 $found['posts_images_ids'] = is_array( $posts_images_ids ) ? array_unique( $posts_images_ids ) : array();
386 $found['posts_images_vc'] = is_array( $posts_images_vc ) ? array_unique( $posts_images_vc ) : array();
387 $found['galleries_images'] = is_array( $galleries_images ) ? array_unique( $galleries_images ) : array();
388 $found['galleries_images_vc'] = is_array( $galleries_images_vc ) ? array_unique( $galleries_images_vc ) : array();
389 $found['galleries_images_fb'] = is_array( $galleries_images_fb ) ? array_unique( $galleries_images_fb ) : array();
390 $found['galleries_images_wc'] = is_array( $galleries_images_wc ) ? array_unique( $galleries_images_wc ) : array();
391 $found['widgets_images'] = is_array( $widgets_images ) ? array_unique( $widgets_images ) : array();
392 set_transient( "wpmc_posts_images_urls", $found['posts_images_urls'], 60 * 60 * 2 );
393 set_transient( "wpmc_posts_images_ids", $found['posts_images_ids'], 60 * 60 * 2 );
394 set_transient( "wpmc_posts_images_visualcomposer", $found['posts_images_vc'], 60 * 60 * 2 );
395 set_transient( "wpmc_galleries_images_visualcomposer", $found['galleries_images_vc'], 60 * 60 * 2 );
396 set_transient( "wpmc_galleries_images_fusionbuilder", $found['galleries_images_fb'], 60 * 60 * 2 );
397 set_transient( "wpmc_galleries_images_woocommerce", $found['galleries_images_wc'], 60 * 60 * 2 );
398 set_transient( "wpmc_galleries_images", $found['galleries_images'], 60 * 60 * 2 );
399 set_transient( "wpmc_widgets_images", $found['widgets_images'], 60 * 60 * 2 );
400 }
401 if ( $finished && get_option( 'wpmc_debuglogs', false ) ) {
402 $this->log( print_r( $found, true ) );
403 }
404 echo json_encode(
405 array(
406 'success' => true,
407 'finished' => $finished,
408 'limit' => $limit + $limitsize,
409 'found' => $found,
410 'message' => __( "Posts checked.", 'media-cleaner' ) )
411 );
412 die();
413 }
414
415 function log( $data, $force = false ) {
416 if ( !get_option( 'wpmc_debuglogs', false ) && !$force )
417 return;
418 $fh = fopen( trailingslashit( dirname(__FILE__) ) . '/media-cleaner.log', 'a' );
419 $date = date( "Y-m-d H:i:s" );
420 fwrite( $fh, "$date: {$data}\n" );
421 fclose( $fh );
422 }
423
424 function wp_ajax_wpmc_scan() {
425 global $wpdb;
426
427 $method = get_option( 'wpmc_method', 'media' );
428 if ( !$this->admin->is_registered() )
429 $method = 'media';
430 $path = isset( $_POST['path'] ) ? $_POST['path'] : null;
431 $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
432 $limitsize = get_option( 'wpmc_medias_buffer', 500 );
433
434 if ( $method == 'files' ) {
435 $output = apply_filters( 'wpmc_list_uploaded_files', array(
436 'results' => array(), 'success' => false, 'message' => __( "Unavailable.", 'media-cleaner' )
437 ), $path );
438 echo json_encode( $output );
439 die();
440 }
441
442 if ( $method == 'media' ) {
443 // Prevent double scanning by removing filesystem entries that we have DB entries for
444 $results = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
445 WHERE p.post_status = 'inherit'
446 AND p.post_type = 'attachment'
447 LIMIT %d, %d", $limit, $limitsize
448 )
449 );
450 $finished = count( $results ) < $limitsize;
451 echo json_encode(
452 array(
453 'results' => $results,
454 'success' => true,
455 'finished' => $finished,
456 'limit' => $limit + $limitsize,
457 'message' => __( "Medias retrieved.", 'media-cleaner' ) )
458 );
459 die();
460 }
461
462 // No task.
463 echo json_encode( array( 'success' => false, 'message' => __( "No task.", 'media-cleaner' ) ) );
464 die();
465 }
466
467 /**
468 *
469 * HELPERS
470 *
471 */
472
473 function wpmc_trashdir() {
474 $upload_folder = wp_upload_dir();
475 return trailingslashit( $upload_folder['basedir'] ) . 'wpmc-trash';
476 }
477
478 function wpmc_check_db() {
479 global $wpdb;
480 $tbl_m = $wpdb->prefix . 'wpmcleaner';
481 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 ) ) ) {
482 wpmc_activate();
483 }
484 }
485
486 /**
487 *
488 * DELETE / SCANNING / RESET
489 *
490 */
491
492 function wpmc_recover_file( $path ) {
493 $basedir = wp_upload_dir();
494 $originalPath = trailingslashit( $basedir['basedir'] ) . $path;
495 $trashPath = trailingslashit( $this->wpmc_trashdir() ) . $path;
496 $path_parts = pathinfo( $originalPath );
497 if ( !file_exists( $path_parts['dirname'] ) && !wp_mkdir_p( $path_parts['dirname'] ) ) {
498 die( 'Failed to create folder.' );
499 }
500 if ( !file_exists( $trashPath ) ) {
501 $this->log( "The file $originalPath actually does not exist in the trash." );
502 return true;
503 }
504 if ( !rename( $trashPath, $originalPath ) ) {
505 die( 'Failed to move the file.' );
506 }
507 return true;
508 }
509
510 function wpmc_recover( $id ) {
511 global $wpdb;
512 $table_name = $wpdb->prefix . "wpmcleaner";
513 $issue = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ), OBJECT );
514 $issue->path = stripslashes( $issue->path );
515
516 // Files
517 if ( $issue->type == 0 ) {
518 $this->wpmc_recover_file( $issue->path );
519 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 0 WHERE id = %d", $id ) );
520 return true;
521 }
522 // Media
523 else if ( $issue->type == 1 ) {
524
525 // Copy the main file back
526 $fullpath = get_attached_file( $issue->postId );
527 $mainfile = $this->wpmc_clean_uploaded_filename( $fullpath );
528 $baseUp = pathinfo( $mainfile );
529 $baseUp = $baseUp['dirname'];
530 $file = $this->wpmc_clean_uploaded_filename( $fullpath );
531 if ( !$this->wpmc_recover_file( $file ) ) {
532 $this->log( "Could not recover $file." );
533 error_log( "Media Cleaner: Could not recover $file." );
534 }
535
536 // If images, copy the other files as well
537 $meta = wp_get_attachment_metadata( $issue->postId );
538 $isImage = isset( $meta, $meta['width'], $meta['height'] );
539 $sizes = $this->wpmc_get_image_sizes();
540 if ( $isImage && isset( $meta['sizes'] ) ) {
541 foreach ( $meta['sizes'] as $name => $attr ) {
542 if ( isset( $attr['file'] ) ) {
543 $filepath = wp_upload_dir();
544 $filepath = $filepath['basedir'];
545 $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
546 $file = $this->wpmc_clean_uploaded_filename( $filepath );
547 if ( !$this->wpmc_recover_file( $file ) ) {
548 $this->log( "Could not recover $file." );
549 error_log( "Media Cleaner: Could not recover $file." );
550 }
551 }
552 }
553 }
554 if ( !wp_untrash_post( $issue->postId ) ) {
555 die( "Failed to untrash Media {$issue->postId}." );
556 }
557 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 0 WHERE id = %d", $id ) );
558 return true;
559 }
560 }
561
562 function wpmc_trash_file( $fileIssuePath ) {
563 global $wpdb;
564 $basedir = wp_upload_dir();
565 $originalPath = trailingslashit( $basedir['basedir'] ) . $fileIssuePath;
566 $trashPath = trailingslashit( $this->wpmc_trashdir() ) . $fileIssuePath;
567 $path_parts = pathinfo( $trashPath );
568
569 try {
570 if ( !file_exists( $path_parts['dirname'] ) && !wp_mkdir_p( $path_parts['dirname'] ) ) {
571 return false;
572 }
573 // Rename the file (move). 'is_dir' is just there for security (no way we should move a whole directory)
574 if ( is_dir( $originalPath ) ) {
575 $this->log( "Attempted to delete a directory instead of a file ($originalPath). Can't do that." );
576 error_log( "Media Cleaner: Attempted to delete a directory instead of a file ($originalPath). Can't do that." );
577 return false;
578 }
579 if ( !file_exists( $originalPath ) ) {
580 $this->log( "The file $originalPath actually does not exist." );
581 return true;
582 }
583 if ( !rename( $originalPath, $trashPath ) ) {
584 return false;
585 }
586 }
587 catch ( Exception $e ) {
588 return false;
589 }
590 $this->wpmc_clean_dir( dirname( $originalPath ) );
591 return true;
592 }
593
594 function wpmc_ignore( $id ) {
595 global $wpdb;
596 $table_name = $wpdb->prefix . "wpmcleaner";
597 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET ignored = 1 WHERE id = %d", $id ) );
598 return true;
599 }
600
601 function wpmc_endsWith( $haystack, $needle )
602 {
603 $length = strlen( $needle );
604 if ( $length == 0 )
605 return true;
606 return ( substr( $haystack, -$length ) === $needle );
607 }
608
609 function wpmc_clean_dir( $dir ) {
610 if ( !file_exists( $dir ) )
611 return;
612 else if ( $this->wpmc_endsWith( $dir, 'uploads' ) )
613 return;
614 $found = array_diff( scandir( $dir ), array( '.', '..' ) );
615 if ( count( $found ) < 1 ) {
616 if ( rmdir( $dir ) ) {
617 $this->wpmc_clean_dir( dirname( $dir ) );
618 }
619 }
620 }
621
622 function wpmc_delete( $id ) {
623 global $wpdb;
624 $table_name = $wpdb->prefix . "wpmcleaner";
625 $issue = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $id ), OBJECT );
626 $regex = "^(.*)(\\s\\(\\+.*)$";
627 $issue->path = preg_replace('/'.$regex.'/i', '$1', $issue->path); // remove " (+ 6 files)" from path
628
629 // Make sure there isn't a media DB entry
630 if ( $issue->type == 0 ) {
631 $attachmentid = $this->wpmc_find_attachment_id_by_file( $issue->path );
632 if ( $attachmentid ) {
633 $this->log( "Issue listed as filesystem but Media {$attachmentid} exists." );
634 error_log( "Media Cleaner: Issue listed as filesystem but Media {$attachmentid} exists." );
635 }
636 }
637
638 if ( $issue->type == 0 ) {
639
640 if ( $issue->deleted == 0 ) {
641 // Move file to the trash
642 if ( $this->wpmc_trash_file( $issue->path ) )
643 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 1 WHERE id = %d", $id ) );
644 return true;
645 }
646 else {
647 // Delete file from the trash
648 $trashPath = trailingslashit( $this->wpmc_trashdir() ) . $issue->path;
649 if ( !unlink( $trashPath ) ) {
650 $this->log( "Failed to delete the file." );
651 error_log( "Media Cleaner: Failed to delete the file." );
652 }
653 $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE id = %d", $id ) );
654 $this->wpmc_clean_dir( dirname( $trashPath ) );
655 return true;
656 }
657 }
658
659 if ( $issue->type == 1 ) {
660 if ( $issue->deleted == 0 && MEDIA_TRASH ) {
661 // Move Media to trash
662 // Let's copy the images to the trash so that it can be recovered.
663 $fullpath = get_attached_file( $issue->postId );
664 $mainfile = $this->wpmc_clean_uploaded_filename( $fullpath );
665 $baseUp = pathinfo( $mainfile );
666 $baseUp = $baseUp['dirname'];
667 $file = $this->wpmc_clean_uploaded_filename( $fullpath );
668 if ( !$this->wpmc_trash_file( $file ) ) {
669 $this->log( "Could not trash $file." );
670 error_log( "Media Cleaner: Could not trash $file." );
671 }
672
673 // If images, check the other files as well
674 $meta = wp_get_attachment_metadata( $issue->postId );
675 $isImage = isset( $meta, $meta['width'], $meta['height'] );
676 $sizes = $this->wpmc_get_image_sizes();
677 if ( $isImage && isset( $meta['sizes'] ) ) {
678 foreach ( $meta['sizes'] as $name => $attr ) {
679 if ( isset( $attr['file'] ) ) {
680 $filepath = wp_upload_dir();
681 $filepath = $filepath['basedir'];
682 $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
683 $file = $this->wpmc_clean_uploaded_filename( $filepath );
684 if ( !$this->wpmc_trash_file( $file ) ) {
685 $this->log( "Could not trash $file." );
686 error_log( "Media Cleaner: Could not trash $file." );
687 }
688 }
689 }
690 }
691 wp_delete_attachment( $issue->postId, false );
692 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 1 WHERE id = %d", $id ) );
693 return true;
694 }
695 else {
696 // Trash Media definitely by recovering it (to be like a normal Media) and remove it through the
697 // standard WordPress workflow
698 if ( MEDIA_TRASH )
699 $this->wpmc_recover( $id );
700 wp_delete_attachment( $issue->postId, true );
701 $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE id = %d", $id ) );
702 return true;
703 }
704 }
705 return false;
706 }
707
708 /**
709 *
710 * SCANNING / RESET
711 *
712 */
713
714 function wpmc_check_is_ignore( $file ) {
715 global $wpdb;
716 $table_name = $wpdb->prefix . "wpmcleaner";
717 $count = $wpdb->get_var( "SELECT COUNT(*)
718 FROM $table_name
719 WHERE ignored = 1
720 AND path LIKE '%". esc_sql( $wpdb->esc_like( $file ) ) . "%'" );
721 if ( $count > 0 ) {
722 $this->log( "Could not trash $file." );
723 }
724 return ($count > 0);
725 }
726
727 function wpmc_find_attachment_id_by_file ($file) {
728 global $wpdb;
729 $postmeta_table_name = $wpdb->prefix . 'postmeta';
730 $file = $this->wpmc_clean_uploaded_filename( $file );
731 $sql = $wpdb->prepare( "SELECT post_id
732 FROM {$postmeta_table_name}
733 WHERE meta_key = '_wp_attached_file'
734 AND meta_value = %s", $file
735 );
736 $ret = $wpdb->get_var( $sql );
737 if ( empty( $ret ) )
738 $this->log( "File $file not found as _wp_attached_file (Library)." );
739 else {
740 $this->log( "File $file found as Media $ret." );
741 }
742 return $ret;
743 }
744
745 function wpmc_get_image_sizes() {
746 $sizes = array();
747 global $_wp_additional_image_sizes;
748 foreach ( get_intermediate_image_sizes() as $s ) {
749 $crop = false;
750 if ( isset( $_wp_additional_image_sizes[$s] ) ) {
751 $width = intval( $_wp_additional_image_sizes[$s]['width'] );
752 $height = intval( $_wp_additional_image_sizes[$s]['height'] );
753 $crop = $_wp_additional_image_sizes[$s]['crop'];
754 } else {
755 $width = get_option( $s.'_size_w' );
756 $height = get_option( $s.'_size_h' );
757 $crop = get_option( $s.'_crop' );
758 }
759 $sizes[$s] = array( 'width' => $width, 'height' => $height, 'crop' => $crop );
760 }
761 return $sizes;
762 }
763
764 function wpmc_clean_url_direct( &$url ) {
765 $url = $this->wpmc_clean_url( $url );
766 }
767
768 // From a url to the shortened and cleaned url (for example '2013/02/file.png')
769 function wpmc_clean_url( $url ) {
770 $upload_folder = wp_upload_dir();
771 $baseurl = $upload_folder['baseurl'];
772 $baseurl = str_replace( 'https://', 'http://', $baseurl );
773 $baseurl = str_replace( 'http://www.', 'http://', $baseurl );
774 $url = str_replace( 'https://', 'http://', $url );
775 $url = str_replace( 'http://www.', 'http://', $url );
776 $url = str_replace( $baseurl, '', $url );
777 $url = trim( $url, "/" );
778 return $url;
779 }
780
781 // From a fullpath to the shortened and cleaned path (for example '2013/02/file.png')
782 function wpmc_clean_uploaded_filename( $fullpath ) {
783 $upload_folder = wp_upload_dir();
784 $basedir = $upload_folder['basedir'];
785 $file = str_replace( $basedir, '', $fullpath );
786 $file = trim( $file, "/" );
787 return $file;
788 }
789
790 function wpmc_check_media( $attachmentId ) {
791
792 $this->last_analysis = "N/A";
793
794 // Is it an image?
795 $meta = wp_get_attachment_metadata( $attachmentId );
796 $isImage = isset( $meta, $meta['width'], $meta['height'] );
797
798 // Get the main file
799 global $wpdb;
800 $fullpath = get_attached_file( $attachmentId );
801 $mainfile = $this->wpmc_clean_uploaded_filename( $fullpath );
802 $baseUp = pathinfo( $mainfile );
803 $baseUp = $baseUp['dirname'];
804 $size = 0;
805 $countfiles = 0;
806 $issue = 'NO_CONTENT';
807 if ( file_exists( $fullpath ) ) {
808 $size = filesize( $fullpath );
809
810 // ANALYSIS
811 $this->last_analysis = "NONE";
812 $this->log( "Checking Media #{$attachmentId}: {$mainfile}" );
813 if ( $this->wpmc_check_is_ignore( $mainfile, $attachmentId ) ) {
814 $this->last_analysis = "IGNORED";
815 return true;
816 }
817 if ( $this->checkers->has_background_or_header( $mainfile, $attachmentId ) ) {
818 $this->last_analysis = "THEME";
819 return true;
820 }
821 if ( $this->checkers->has_content( $mainfile, $attachmentId ) ) {
822 if ( empty( $this->last_analysis ) )
823 $this->last_analysis = "CONTENT";
824 return true;
825 }
826 if ( $this->checkers->check_in_gallery( $mainfile, $attachmentId ) ) {
827 $this->last_analysis = "GALLERY";
828 return true;
829 }
830 if ( $this->checkers->has_meta( $mainfile, $attachmentId ) ) {
831 $this->last_analysis = "META";
832 return true;
833 }
834
835 // If images, check the other files as well
836 $countfiles = 0;
837 $sizes = $this->wpmc_get_image_sizes();
838 if ( $isImage && isset( $meta['sizes'] ) ) {
839 foreach ( $meta['sizes'] as $name => $attr ) {
840 if ( isset( $attr['file'] ) ) {
841 $filepath = wp_upload_dir();
842 $filepath = $filepath['basedir'];
843 $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
844 if ( file_exists( $filepath ) ) {
845 $size += filesize( $filepath );
846 }
847 $file = $this->wpmc_clean_uploaded_filename( $filepath );
848 $countfiles++;
849 $this->log( "Checking Media #{$attachmentId}: {$file}" );
850
851 // ANALYSIS
852 if ( $this->checkers->has_content( $file, $attachmentId ) ) {
853 $this->last_analysis = "CONTENT";
854 return true;
855 }
856 if ( $this->checkers->check_in_gallery( $file, $attachmentId ) ) {
857 $this->last_analysis = "GALLERY";
858 return true;
859 }
860 if ( $this->checkers->has_background_or_header( $file, $attachmentId ) ) {
861 $this->last_analysis = "THEME";
862 return true;
863 }
864 if ( $this->checkers->has_meta( $file, $attachmentId ) ) {
865 $this->last_analysis = "META";
866 return true;
867 }
868
869 }
870 }
871 }
872 } else {
873 $issue = 'ORPHAN_MEDIA';
874 }
875
876 $table_name = $wpdb->prefix . "wpmcleaner";
877 $wpdb->insert( $table_name,
878 array(
879 'time' => current_time('mysql'),
880 'type' => 1,
881 'size' => $size,
882 'path' => $mainfile . ( $countfiles > 0 ? ( " (+ " . $countfiles . " files)" ) : "" ),
883 'postId' => $attachmentId,
884 'issue' => $issue
885 )
886 );
887 return false;
888 }
889
890 // Delete all issues
891 function wpmc_reset_issues( $includingIgnored = false ) {
892 global $wpdb;
893 $table_name = $wpdb->prefix . "wpmcleaner";
894 if ( $includingIgnored ) {
895 $wpdb->query( "DELETE FROM $table_name WHERE deleted = 0" );
896 }
897 else {
898 $wpdb->query( "DELETE FROM $table_name WHERE ignored = 0 AND deleted = 0" );
899 }
900 if ( file_exists( plugin_dir_path( __FILE__ ) . '/media-cleaner.log' ) ) {
901 file_put_contents( plugin_dir_path( __FILE__ ) . '/media-cleaner.log', '' );
902 }
903 delete_transient( "wpmc_posts_images_urls" );
904 delete_transient( "wpmc_posts_images_ids" );
905 delete_transient( "wpmc_posts_images_visualcomposer" );
906 delete_transient( "wpmc_galleries_images_visualcomposer" );
907 delete_transient( "wpmc_galleries_images_fusionbuilder" );
908 delete_transient( "wpmc_galleries_images_woocommerce" );
909 delete_transient( "wpmc_galleries_images" );
910 delete_transient( "wpmc_widgets_images" );
911 }
912
913 /**
914 *
915 * DASHBOARD
916 *
917 */
918
919 function admin_inline_js() {
920 echo "<script type='text/javascript'>\n";
921 echo 'var wpmc_cfg = {
922 delay: ' . get_option( 'wpmc_delay', 100 ) . ',
923 analysisBuffer: ' . get_option( 'wpmc_analysis_buffer', 5 ) . ',
924 isPro: ' . ( $this->admin->is_registered() ? '1' : '0') . ',
925 scanFiles: ' . ( ( get_option( 'wpmc_method', 'media' ) == 'files' && $this->admin->is_registered() ) ? '1' : '0' ) . ',
926 scanMedia: ' . ( get_option( 'wpmc_method', 'media' ) == 'media' ? '1' : '0' ) . ' };';
927 echo "\n</script>";
928 }
929
930 function echo_issue( $issue ) {
931 if ( $issue == 'NO_CONTENT' ) {
932 _e( "Seems not in use.", 'media-cleaner' );
933 }
934 else if ( $issue == 'NO_MEDIA' ) {
935 _e( "Not in Media Library.", 'media-cleaner' );
936 }
937 else if ( $issue == 'ORPHAN_RETINA' ) {
938 _e( "Orphan retina.", 'media-cleaner' );
939 }
940 else if ( $issue == 'ORPHAN_MEDIA' ) {
941 _e( "File not found.", 'media-cleaner' );
942 }
943 else {
944 echo $issue;
945 }
946 }
947
948 function media_row_actions( $actions, $post ) {
949 global $current_screen;
950 if ( 'upload' != $current_screen->id )
951 return $actions;
952 global $wpdb;
953 $table_name = $wpdb->prefix . "wpmcleaner";
954 $res = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE postId = %d", $post->ID ) );
955 if ( !empty( $res ) && isset( $actions['delete'] ) )
956 $actions['delete'] = "<a href='?page=media-cleaner&view=deleted'>Delete with Media Cleaner</a>";
957 if ( !empty( $res ) && isset( $actions['trash'] ) )
958 $actions['trash'] = "<a href='?page=media-cleaner'>Trash with Media Cleaner</a>";
959 if ( !empty( $res ) && isset( $actions['untrash'] ) ) {
960 $actions['untrash'] = "<a href='?page=media-cleaner&view=deleted'>Restore with Media Cleaner</a>";
961 }
962 return $actions;
963 }
964
965 function wpmc_screen() {
966 global $wplr;
967 $this->wpmc_check_db();
968 ?>
969 <div class='wrap'>
970
971 <?php
972 echo $this->admin->display_title( "Media Cleaner" );
973 global $wpdb;
974 $posts_per_page = get_user_meta( get_current_user_id(), 'upload_per_page', true );
975 if ( empty( $posts_per_page ) )
976 $posts_per_page = 20;
977 $view = isset ( $_GET[ 'view' ] ) ? sanitize_text_field( $_GET[ 'view' ] ) : "issues";
978 $paged = isset ( $_GET[ 'paged' ] ) ? sanitize_text_field( $_GET[ 'paged' ] ) : 1;
979 $reset = isset ( $_GET[ 'reset' ] ) ? $_GET[ 'reset' ] : 0;
980 if ( $reset ) {
981 wpmc_reset();
982 $this->wpmc_reset_issues();
983 }
984 $s = isset ( $_GET[ 's' ] ) ? sanitize_text_field( $_GET[ 's' ] ) : null;
985 $table_name = $wpdb->prefix . "wpmcleaner";
986 $issues_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
987 $total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
988 $trash_total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 1" );
989 $ignored_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE ignored = 1" );
990 $deleted_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE deleted = 1" );
991
992 if ( $view == 'deleted' ) {
993 $items_count = $deleted_count;
994 $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
995 FROM $table_name WHERE ignored = 0 AND deleted = 1 AND path LIKE %s
996 ORDER BY time
997 DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
998 }
999 else if ( $view == 'ignored' ) {
1000 $items_count = $ignored_count;
1001 $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
1002 FROM $table_name
1003 WHERE ignored = 1 AND deleted = 0 AND path LIKE %s
1004 ORDER BY time
1005 DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
1006 }
1007 else {
1008 $items_count = $issues_count;
1009 $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
1010 FROM $table_name
1011 WHERE ignored = 0 AND deleted = 0 AND path LIKE %s
1012 ORDER BY time
1013 DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
1014 }
1015 ?>
1016
1017 <style>
1018 #wpmc-pages {
1019 float: right;
1020 position: relative;
1021 top: 12px;
1022 }
1023
1024 #wpmc-pages a {
1025 text-decoration: none;
1026 border: 1px solid black;
1027 padding: 2px 5px;
1028 border-radius: 4px;
1029 background: #E9E9E9;
1030 color: lightslategrey;
1031 border-color: #BEBEBE;
1032 }
1033
1034 #wpmc-pages .current {
1035 font-weight: bold;
1036 }
1037 </style>
1038
1039 <div style='margin-top: 0px; background: #FFF; padding: 5px; border-radius: 4px; height: 28px; box-shadow: 0px 0px 6px #C2C2C2;'>
1040
1041 <!-- SCAN -->
1042 <?php if ( $view != 'deleted' ) { ?>
1043 <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>
1044 <?php } ?>
1045
1046 <!-- PAUSE -->
1047 <?php if ( $view != 'deleted' ) { ?>
1048 <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>
1049 <?php } ?>
1050
1051 <!-- DELETE SELECTED -->
1052 <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>
1053 <?php if ( $view == 'deleted' ) { ?>
1054 <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>
1055 <?php } ?>
1056
1057 <!-- IGNORE SELECTED -->
1058 <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 _e("Ignore", 'media-cleaner'); ?></a>
1059
1060 <!-- RESET -->
1061 <?php if ( $view != 'deleted' ) { ?>
1062 <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>
1063 <?php } ?>
1064
1065 <!-- DELETE ALL -->
1066 <?php if ( $view == 'deleted' ) { ?>
1067 <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>
1068 <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>
1069 <?php } else { ?>
1070 <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>
1071 <?php } ?>
1072
1073 <form id="posts-filter" action="upload.php" method="get" style='float: right;'>
1074 <p class="search-box" style='margin-left: 5px; float: left;'>
1075 <input type="search" name="s" style="width: 120px;" value="<?php echo $s ? $s : ""; ?>">
1076 <input type="hidden" name="page" value="media-cleaner">
1077 <input type="hidden" name="view" value="<?php echo $view; ?>">
1078 <input type="hidden" name="paged" value="<?php echo $paged; ?>">
1079 <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>
1080 </p>
1081 </form>
1082
1083 <!-- PROGRESS -->
1084 <span style='margin-left: 12px; font-size: 15px; top: 5px; position: relative; color: #747474;' id='wpmc_progression'></span>
1085
1086 </div>
1087
1088 <p>
1089 <?php
1090 $method = get_option( 'wpmc_method', 'media' );
1091 if ( !$this->admin->is_registered() )
1092 $method = 'media';
1093
1094 $hide_warning = get_option( 'wpmc_hide_warning', false );
1095
1096 if ( !$hide_warning ) {
1097 _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> <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' );
1098 }
1099
1100 if ( !MEDIA_TRASH ) {
1101 _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>" );
1102 }
1103
1104 if ( !$this->admin->is_registered() ) {
1105 echo "<div class='notice notice-info'><p>";
1106 _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' );
1107 echo "</p></div>";
1108 }
1109
1110 $anychecks = get_option( 'wpmc_posts', true ) || get_option(' wpmc_galleries', false ) ||
1111 get_option(' wpmc_postmeta', true );
1112 $check_library = get_option(' wpmc_media_library', false );
1113
1114 if ( $method == 'media' ) {
1115 if ( !$anychecks )
1116 _e( "<div class='error'><p>Media Cleaner will analyze your Media Library. There is however <b>nothing marked to be check</b> in the Settings.</p></div>", 'media-cleaner' );
1117 else
1118 _e( "<div class='notice notice-success'><p>Media Cleaner will analyze your Media Library.</p></div>", 'media-cleaner' );
1119 }
1120 else if ( $method == 'files' ) {
1121 if ( !$anychecks && !$check_library )
1122 _e( "<div class='error'><p>Media Cleaner will analyze your Filesystem. There is however <b>nothing marked to be check</b> in the Settings.</p></div>", 'media-cleaner' );
1123 else
1124 _e( "<div class='notice notice-success'><p>Media Cleaner will analyze your Filesystem.</p></div>", 'media-cleaner' );
1125 }
1126
1127 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 ) );
1128 ?>
1129 </p>
1130
1131 <div id='wpmc-pages'>
1132 <?php
1133 echo paginate_links(array(
1134 'base' => '?page=media-cleaner&s=' . urlencode($s) . '&view=' . $view . '%_%',
1135 'current' => $paged,
1136 'format' => '&paged=%#%',
1137 'total' => ceil( $items_count / $posts_per_page ),
1138 'prev_next' => false
1139 ));
1140 ?>
1141 </div>
1142
1143 <ul class="subsubsub">
1144 <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> |
1145 <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> |
1146 <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>
1147 </ul>
1148
1149 <table id='wpmc-table' class='wp-list-table widefat fixed media'>
1150
1151 <thead>
1152 <tr>
1153 <th scope="col" id="cb" class="manage-column column-cb check-column"><input id="wpmc-cb-select-all" type="checkbox"></th>
1154 <?php if ( !get_option( 'wpmc_hide_thumbnails', false ) ): ?>
1155 <th style='width: 64px;'><?php _e( 'Thumb', 'media-cleaner' ) ?></th>
1156 <?php endif; ?>
1157 <th style='width: 50px;'><?php _e( 'Type', 'media-cleaner' ) ?></th>
1158 <th style='width: 80px;'><?php _e( 'Origin', 'media-cleaner' ) ?></th>
1159
1160 <?php if ( !empty( $wplr ) ): ?>
1161 <th style='width: 70px;'><?php _e( 'LR ID', 'media-cleaner' ) ?></th>
1162 <?php endif; ?>
1163
1164 <th><?php _e( 'Path', 'media-cleaner' ) ?></th>
1165 <th style='width: 220px;'><?php _e( 'Issue', 'media-cleaner' ) ?></th>
1166 <th style='width: 80px; text-align: right;'><?php _e( 'Size', 'media-cleaner' ) ?></th>
1167 </tr>
1168 </thead>
1169
1170 <tbody>
1171 <?php
1172 foreach ( $items as $issue ) {
1173 $regex = "^(.*)(\\s\\(\\+.*)$";
1174 $issue->path = preg_replace( '/' .$regex . '/i', '$1', $issue->path );
1175 ?>
1176 <tr>
1177 <td><input type="checkbox" name="id" value="<?php echo $issue->id ?>"></td>
1178 <?php if ( !get_option( 'wpmc_hide_thumbnails', false ) ): ?>
1179 <td>
1180 <?php
1181 if ( $issue->deleted == 0 ) {
1182 if ( $issue ->type == 0 ) {
1183 // FILE
1184 $upload_dir = wp_upload_dir();
1185 $url = htmlspecialchars( $upload_dir['baseurl'] . '/' . $issue->path, ENT_QUOTES );
1186 echo "<a target='_blank' href='" . $url .
1187 "'><img style='max-width: 48px; max-height: 48px;' src='" . $url . "' /></a>";
1188 }
1189 else {
1190 // MEDIA
1191 $attachmentsrc = wp_get_attachment_image_src( $issue->postId, 'thumbnail' );
1192 $attachmentsrc_clean = htmlspecialchars( $attachmentsrc[0], ENT_QUOTES );
1193 echo "<a target='_blank' href='" . $attachmentsrc_clean .
1194 "'><img style='max-width: 48px; max-height: 48px;' src='" .
1195 $attachmentsrc_clean . "' />";
1196 }
1197 }
1198 if ( $issue->deleted == 1 ) {
1199 $upload_dir = wp_upload_dir();
1200 $url = htmlspecialchars( $upload_dir['baseurl'] . '/wpmc-trash/' . $issue->path, ENT_QUOTES );
1201 echo "<a target='_blank' href='" . $url .
1202 "'><img style='max-width: 48px; max-height: 48px;' src='" . $url . "' /></a>";
1203 }
1204 ?>
1205 </td>
1206 <?php endif; ?>
1207 <td><?php echo $issue->type == 0 ? 'FILE' : 'MEDIA'; ?></td>
1208 <td><?php echo $issue->type == 0 ? 'Filesystem' : ("<a href='post.php?post=" .
1209 $issue->postId . "&action=edit'>ID " . $issue->postId . "</a>"); ?></td>
1210 <?php if ( !empty( $wplr ) ) { $info = $wplr->get_sync_info( $issue->postId ); ?>
1211 <td style='width: 70px;'><?php echo ( !empty( $info ) && $info->lr_id ? $info->lr_id : "" ); ?></td>
1212 <?php } ?>
1213 <td><?php echo stripslashes( $issue->path ); ?></td>
1214 <td><?php $this->echo_issue( $issue->issue ); ?></td>
1215 <td style='text-align: right;'><?php echo number_format( $issue->size / 1000, 2 ); ?> KB</td>
1216 </tr>
1217 <?php } ?>
1218 </tbody>
1219
1220 <tfoot>
1221 <tr><th></th>
1222 <?php if ( !get_option( 'hide_thumbnails', false ) ): ?>
1223 <th></th>
1224 <?php endif; ?>
1225 <th><?php _e( 'Type', 'media-cleaner' ) ?></th><th><?php _e( 'Origin', 'media-cleaner' ) ?></th>
1226 <?php if ( !empty( $wplr ) ): ?>
1227 <th style='width: 70px;'><?php _e( 'LR ID', 'media-cleaner' ) ?></th>
1228 <?php endif; ?>
1229 <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>
1230 </tfoot>
1231
1232 </table>
1233 </wrap>
1234
1235 <?php
1236 }
1237
1238 function admin_menu() {
1239 //load_plugin_textdomain( 'media-cleaner', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
1240 add_media_page( 'Media Cleaner', 'Cleaner', 'manage_options', 'media-cleaner', array( $this, 'wpmc_screen' ) );
1241 }
1242
1243 function wp_enqueue_scripts () {
1244 wp_enqueue_style( 'media-cleaner-css', plugins_url( '/media-cleaner.css', __FILE__ ) );
1245 wp_enqueue_script( 'media-cleaner', plugins_url( '/media-cleaner.js', __FILE__ ), array( 'jquery' ), "3.7.0", true );
1246 }
1247 }
1248
1249
1250 /*
1251 INSTALL / UNINSTALL
1252 */
1253
1254 register_activation_hook( __FILE__, 'wpmc_activate' );
1255 register_deactivation_hook( __FILE__, 'wpmc_uninstall' );
1256 register_uninstall_hook( __FILE__, 'wpmc_uninstall' );
1257
1258 function wpmc_reset() {
1259 wpmc_uninstall();
1260 wpmc_activate();
1261 }
1262
1263 function wpmc_activate () {
1264 global $wpdb;
1265 $table_name = $wpdb->prefix . "wpmcleaner";
1266 $charset_collate = $wpdb->get_charset_collate();
1267 $sql = "CREATE TABLE $table_name (
1268 id BIGINT(20) NOT NULL AUTO_INCREMENT,
1269 time DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL,
1270 type TINYINT(1) NOT NULL,
1271 postId BIGINT(20) NULL,
1272 path TINYTEXT NULL,
1273 size INT(9) NULL,
1274 ignored TINYINT(1) NOT NULL DEFAULT 0,
1275 deleted TINYINT(1) NOT NULL DEFAULT 0,
1276 issue TINYTEXT NOT NULL,
1277 UNIQUE KEY id (id)
1278 ) " . $charset_collate . ";";
1279 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
1280 dbDelta( $sql );
1281
1282 $upload_folder = wp_upload_dir();
1283 $basedir = $upload_folder['basedir'];
1284 if ( !is_writable( $basedir ) ) {
1285 echo '<div class="error"><p>' . __( 'The directory for uploads is not writable. Media Cleaner will only be able to scan.', 'media-cleaner' ) . '</p></div>';
1286 }
1287 }
1288
1289 function wpmc_uninstall () {
1290 global $wpdb;
1291 $table_name = $wpdb->prefix . "wpmcleaner";
1292 $wpdb->query("DROP TABLE IF EXISTS $table_name");
1293 }
1294