PluginProbe ʕ •ᴥ•ʔ
Media Cleaner: Clean your WordPress! / 4.2.3
Media Cleaner: Clean your WordPress! v4.2.3
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
1293 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 meta_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 }
635 }
636
637 if ( $issue->type == 0 ) {
638
639 if ( $issue->deleted == 0 ) {
640 // Move file to the trash
641 if ( $this->wpmc_trash_file( $issue->path ) )
642 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 1 WHERE id = %d", $id ) );
643 return true;
644 }
645 else {
646 // Delete file from the trash
647 $trashPath = trailingslashit( $this->wpmc_trashdir() ) . $issue->path;
648 if ( !unlink( $trashPath ) ) {
649 $this->log( "Failed to delete the file." );
650 error_log( "Media Cleaner: Failed to delete the file." );
651 }
652 $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE id = %d", $id ) );
653 $this->wpmc_clean_dir( dirname( $trashPath ) );
654 return true;
655 }
656 }
657
658 if ( $issue->type == 1 ) {
659 if ( $issue->deleted == 0 && MEDIA_TRASH ) {
660 // Move Media to trash
661 // Let's copy the images to the trash so that it can be recovered.
662 $fullpath = get_attached_file( $issue->postId );
663 $mainfile = $this->wpmc_clean_uploaded_filename( $fullpath );
664 $baseUp = pathinfo( $mainfile );
665 $baseUp = $baseUp['dirname'];
666 $file = $this->wpmc_clean_uploaded_filename( $fullpath );
667 if ( !$this->wpmc_trash_file( $file ) ) {
668 $this->log( "Could not trash $file." );
669 error_log( "Media Cleaner: Could not trash $file." );
670 }
671
672 // If images, check the other files as well
673 $meta = wp_get_attachment_metadata( $issue->postId );
674 $isImage = isset( $meta, $meta['width'], $meta['height'] );
675 $sizes = $this->wpmc_get_image_sizes();
676 if ( $isImage && isset( $meta['sizes'] ) ) {
677 foreach ( $meta['sizes'] as $name => $attr ) {
678 if ( isset( $attr['file'] ) ) {
679 $filepath = wp_upload_dir();
680 $filepath = $filepath['basedir'];
681 $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
682 $file = $this->wpmc_clean_uploaded_filename( $filepath );
683 if ( !$this->wpmc_trash_file( $file ) ) {
684 $this->log( "Could not trash $file." );
685 error_log( "Media Cleaner: Could not trash $file." );
686 }
687 }
688 }
689 }
690 wp_delete_attachment( $issue->postId, false );
691 $wpdb->query( $wpdb->prepare( "UPDATE $table_name SET deleted = 1 WHERE id = %d", $id ) );
692 return true;
693 }
694 else {
695 // Trash Media definitely by recovering it (to be like a normal Media) and remove it through the
696 // standard WordPress workflow
697 if ( MEDIA_TRASH )
698 $this->wpmc_recover( $id );
699 wp_delete_attachment( $issue->postId, true );
700 $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE id = %d", $id ) );
701 return true;
702 }
703 }
704 return false;
705 }
706
707 /**
708 *
709 * SCANNING / RESET
710 *
711 */
712
713 function wpmc_check_is_ignore( $file ) {
714 global $wpdb;
715 $table_name = $wpdb->prefix . "wpmcleaner";
716 $count = $wpdb->get_var( "SELECT COUNT(*)
717 FROM $table_name
718 WHERE ignored = 1
719 AND path LIKE '%". esc_sql( $wpdb->esc_like( $file ) ) . "%'" );
720 if ( $count > 0 ) {
721 $this->log( "Could not trash $file." );
722 }
723 return ($count > 0);
724 }
725
726 function wpmc_find_attachment_id_by_file ($file) {
727 global $wpdb;
728 $postmeta_table_name = $wpdb->prefix . 'postmeta';
729 $file = $this->wpmc_clean_uploaded_filename( $file );
730 $sql = $wpdb->prepare( "SELECT post_id
731 FROM {$postmeta_table_name}
732 WHERE meta_key = '_wp_attached_file'
733 AND meta_value = %s", $file
734 );
735 $ret = $wpdb->get_var( $sql );
736 if ( empty( $ret ) )
737 $this->log( "File $file not found as _wp_attached_file (Library)." );
738 else {
739 $this->log( "File $file found as Media $ret." );
740 }
741 return $ret;
742 }
743
744 function wpmc_get_image_sizes() {
745 $sizes = array();
746 global $_wp_additional_image_sizes;
747 foreach ( get_intermediate_image_sizes() as $s ) {
748 $crop = false;
749 if ( isset( $_wp_additional_image_sizes[$s] ) ) {
750 $width = intval( $_wp_additional_image_sizes[$s]['width'] );
751 $height = intval( $_wp_additional_image_sizes[$s]['height'] );
752 $crop = $_wp_additional_image_sizes[$s]['crop'];
753 } else {
754 $width = get_option( $s.'_size_w' );
755 $height = get_option( $s.'_size_h' );
756 $crop = get_option( $s.'_crop' );
757 }
758 $sizes[$s] = array( 'width' => $width, 'height' => $height, 'crop' => $crop );
759 }
760 return $sizes;
761 }
762
763 function wpmc_clean_url_direct( &$url ) {
764 $url = $this->wpmc_clean_url( $url );
765 }
766
767 // From a url to the shortened and cleaned url (for example '2013/02/file.png')
768 function wpmc_clean_url( $url ) {
769 $upload_folder = wp_upload_dir();
770 $baseurl = $upload_folder['baseurl'];
771 $baseurl = str_replace( 'https://', 'http://', $baseurl );
772 $baseurl = str_replace( 'http://www.', 'http://', $baseurl );
773 $url = str_replace( 'https://', 'http://', $url );
774 $url = str_replace( 'http://www.', 'http://', $url );
775 $url = str_replace( $baseurl, '', $url );
776 $url = trim( $url, "/" );
777 return $url;
778 }
779
780 // From a fullpath to the shortened and cleaned path (for example '2013/02/file.png')
781 function wpmc_clean_uploaded_filename( $fullpath ) {
782 $upload_folder = wp_upload_dir();
783 $basedir = $upload_folder['basedir'];
784 $file = str_replace( $basedir, '', $fullpath );
785 $file = trim( $file, "/" );
786 return $file;
787 }
788
789 function wpmc_check_media( $attachmentId ) {
790
791 $this->last_analysis = "N/A";
792
793 // Is it an image?
794 $meta = wp_get_attachment_metadata( $attachmentId );
795 $isImage = isset( $meta, $meta['width'], $meta['height'] );
796
797 // Get the main file
798 global $wpdb;
799 $fullpath = get_attached_file( $attachmentId );
800 $mainfile = $this->wpmc_clean_uploaded_filename( $fullpath );
801 $baseUp = pathinfo( $mainfile );
802 $baseUp = $baseUp['dirname'];
803 $size = 0;
804 $countfiles = 0;
805 $issue = 'NO_CONTENT';
806 if ( file_exists( $fullpath ) ) {
807 $size = filesize( $fullpath );
808
809 // ANALYSIS
810 $this->last_analysis = "NONE";
811 $this->log( "Checking Media #{$attachmentId}: {$mainfile}" );
812 if ( $this->wpmc_check_is_ignore( $mainfile, $attachmentId ) ) {
813 $this->last_analysis = "IGNORED";
814 return true;
815 }
816 if ( $this->checkers->has_background_or_header( $mainfile, $attachmentId ) ) {
817 $this->last_analysis = "THEME";
818 return true;
819 }
820 if ( $this->checkers->has_content( $mainfile, $attachmentId ) ) {
821 if ( empty( $this->last_analysis ) )
822 $this->last_analysis = "CONTENT";
823 return true;
824 }
825 if ( $this->checkers->check_in_gallery( $mainfile, $attachmentId ) ) {
826 $this->last_analysis = "GALLERY";
827 return true;
828 }
829 if ( $this->checkers->has_meta( $mainfile, $attachmentId ) ) {
830 $this->last_analysis = "META";
831 return true;
832 }
833
834 // If images, check the other files as well
835 $countfiles = 0;
836 $sizes = $this->wpmc_get_image_sizes();
837 if ( $isImage && isset( $meta['sizes'] ) ) {
838 foreach ( $meta['sizes'] as $name => $attr ) {
839 if ( isset( $attr['file'] ) ) {
840 $filepath = wp_upload_dir();
841 $filepath = $filepath['basedir'];
842 $filepath = trailingslashit( $filepath ) . trailingslashit( $baseUp ) . $attr['file'];
843 if ( file_exists( $filepath ) ) {
844 $size += filesize( $filepath );
845 }
846 $file = $this->wpmc_clean_uploaded_filename( $filepath );
847 $countfiles++;
848 $this->log( "Checking Media #{$attachmentId}: {$file}" );
849
850 // ANALYSIS
851 if ( $this->checkers->has_content( $file, $attachmentId ) ) {
852 $this->last_analysis = "CONTENT";
853 return true;
854 }
855 if ( $this->checkers->check_in_gallery( $file, $attachmentId ) ) {
856 $this->last_analysis = "GALLERY";
857 return true;
858 }
859 if ( $this->checkers->has_background_or_header( $file, $attachmentId ) ) {
860 $this->last_analysis = "THEME";
861 return true;
862 }
863 if ( $this->checkers->has_meta( $file, $attachmentId ) ) {
864 $this->last_analysis = "META";
865 return true;
866 }
867
868 }
869 }
870 }
871 } else {
872 $issue = 'ORPHAN_MEDIA';
873 }
874
875 $table_name = $wpdb->prefix . "wpmcleaner";
876 $wpdb->insert( $table_name,
877 array(
878 'time' => current_time('mysql'),
879 'type' => 1,
880 'size' => $size,
881 'path' => $mainfile . ( $countfiles > 0 ? ( " (+ " . $countfiles . " files)" ) : "" ),
882 'postId' => $attachmentId,
883 'issue' => $issue
884 )
885 );
886 return false;
887 }
888
889 // Delete all issues
890 function wpmc_reset_issues( $includingIgnored = false ) {
891 global $wpdb;
892 $table_name = $wpdb->prefix . "wpmcleaner";
893 if ( $includingIgnored ) {
894 $wpdb->query( "DELETE FROM $table_name WHERE deleted = 0" );
895 }
896 else {
897 $wpdb->query( "DELETE FROM $table_name WHERE ignored = 0 AND deleted = 0" );
898 }
899 if ( file_exists( plugin_dir_path( __FILE__ ) . '/media-cleaner.log' ) ) {
900 file_put_contents( plugin_dir_path( __FILE__ ) . '/media-cleaner.log', '' );
901 }
902 delete_transient( "wpmc_posts_images_urls" );
903 delete_transient( "wpmc_posts_images_ids" );
904 delete_transient( "wpmc_posts_images_visualcomposer" );
905 delete_transient( "wpmc_galleries_images_visualcomposer" );
906 delete_transient( "wpmc_galleries_images_fusionbuilder" );
907 delete_transient( "wpmc_galleries_images_woocommerce" );
908 delete_transient( "wpmc_galleries_images" );
909 delete_transient( "wpmc_widgets_images" );
910 }
911
912 /**
913 *
914 * DASHBOARD
915 *
916 */
917
918 function admin_inline_js() {
919 echo "<script type='text/javascript'>\n";
920 echo 'var wpmc_cfg = {
921 delay: ' . get_option( 'wpmc_delay', 100 ) . ',
922 analysisBuffer: ' . get_option( 'wpmc_analysis_buffer', 5 ) . ',
923 isPro: ' . ( $this->admin->is_registered() ? '1' : '0') . ',
924 scanFiles: ' . ( ( get_option( 'wpmc_method', 'media' ) == 'files' && $this->admin->is_registered() ) ? '1' : '0' ) . ',
925 scanMedia: ' . ( get_option( 'wpmc_method', 'media' ) == 'media' ? '1' : '0' ) . ' };';
926 echo "\n</script>";
927 }
928
929 function echo_issue( $issue ) {
930 if ( $issue == 'NO_CONTENT' ) {
931 _e( "Seems not in use.", 'media-cleaner' );
932 }
933 else if ( $issue == 'NO_MEDIA' ) {
934 _e( "Not in Media Library.", 'media-cleaner' );
935 }
936 else if ( $issue == 'ORPHAN_RETINA' ) {
937 _e( "Orphan retina.", 'media-cleaner' );
938 }
939 else if ( $issue == 'ORPHAN_MEDIA' ) {
940 _e( "File not found.", 'media-cleaner' );
941 }
942 else {
943 echo $issue;
944 }
945 }
946
947 function media_row_actions( $actions, $post ) {
948 global $current_screen;
949 if ( 'upload' != $current_screen->id )
950 return $actions;
951 global $wpdb;
952 $table_name = $wpdb->prefix . "wpmcleaner";
953 $res = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE postId = %d", $post->ID ) );
954 if ( !empty( $res ) && isset( $actions['delete'] ) )
955 $actions['delete'] = "<a href='?page=media-cleaner&view=deleted'>Delete with Media Cleaner</a>";
956 if ( !empty( $res ) && isset( $actions['trash'] ) )
957 $actions['trash'] = "<a href='?page=media-cleaner'>Trash with Media Cleaner</a>";
958 if ( !empty( $res ) && isset( $actions['untrash'] ) ) {
959 $actions['untrash'] = "<a href='?page=media-cleaner&view=deleted'>Restore with Media Cleaner</a>";
960 }
961 return $actions;
962 }
963
964 function wpmc_screen() {
965 global $wplr;
966 $this->wpmc_check_db();
967 ?>
968 <div class='wrap'>
969
970 <?php
971 echo $this->admin->display_title( "Media Cleaner" );
972 global $wpdb;
973 $posts_per_page = get_user_meta( get_current_user_id(), 'upload_per_page', true );
974 if ( empty( $posts_per_page ) )
975 $posts_per_page = 20;
976 $view = isset ( $_GET[ 'view' ] ) ? sanitize_text_field( $_GET[ 'view' ] ) : "issues";
977 $paged = isset ( $_GET[ 'paged' ] ) ? sanitize_text_field( $_GET[ 'paged' ] ) : 1;
978 $reset = isset ( $_GET[ 'reset' ] ) ? $_GET[ 'reset' ] : 0;
979 if ( $reset ) {
980 wpmc_reset();
981 $this->wpmc_reset_issues();
982 }
983 $s = isset ( $_GET[ 's' ] ) ? sanitize_text_field( $_GET[ 's' ] ) : null;
984 $table_name = $wpdb->prefix . "wpmcleaner";
985 $issues_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
986 $total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 0" );
987 $trash_total_size = $wpdb->get_var( "SELECT SUM(size) FROM $table_name WHERE ignored = 0 AND deleted = 1" );
988 $ignored_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE ignored = 1" );
989 $deleted_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name WHERE deleted = 1" );
990
991 if ( $view == 'deleted' ) {
992 $items_count = $deleted_count;
993 $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
994 FROM $table_name WHERE ignored = 0 AND deleted = 1 AND path LIKE %s
995 ORDER BY time
996 DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
997 }
998 else if ( $view == 'ignored' ) {
999 $items_count = $ignored_count;
1000 $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
1001 FROM $table_name
1002 WHERE ignored = 1 AND deleted = 0 AND path LIKE %s
1003 ORDER BY time
1004 DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
1005 }
1006 else {
1007 $items_count = $issues_count;
1008 $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
1009 FROM $table_name
1010 WHERE ignored = 0 AND deleted = 0 AND path LIKE %s
1011 ORDER BY time
1012 DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
1013 }
1014 ?>
1015
1016 <style>
1017 #wpmc-pages {
1018 float: right;
1019 position: relative;
1020 top: 12px;
1021 }
1022
1023 #wpmc-pages a {
1024 text-decoration: none;
1025 border: 1px solid black;
1026 padding: 2px 5px;
1027 border-radius: 4px;
1028 background: #E9E9E9;
1029 color: lightslategrey;
1030 border-color: #BEBEBE;
1031 }
1032
1033 #wpmc-pages .current {
1034 font-weight: bold;
1035 }
1036 </style>
1037
1038 <div style='margin-top: 0px; background: #FFF; padding: 5px; border-radius: 4px; height: 28px; box-shadow: 0px 0px 6px #C2C2C2;'>
1039
1040 <!-- SCAN -->
1041 <?php if ( $view != 'deleted' ) { ?>
1042 <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>
1043 <?php } ?>
1044
1045 <!-- PAUSE -->
1046 <?php if ( $view != 'deleted' ) { ?>
1047 <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>
1048 <?php } ?>
1049
1050 <!-- DELETE SELECTED -->
1051 <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>
1052 <?php if ( $view == 'deleted' ) { ?>
1053 <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>
1054 <?php } ?>
1055
1056 <!-- IGNORE SELECTED -->
1057 <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>
1058
1059 <!-- RESET -->
1060 <?php if ( $view != 'deleted' ) { ?>
1061 <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>
1062 <?php } ?>
1063
1064 <!-- DELETE ALL -->
1065 <?php if ( $view == 'deleted' ) { ?>
1066 <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>
1067 <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>
1068 <?php } else { ?>
1069 <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>
1070 <?php } ?>
1071
1072 <form id="posts-filter" action="upload.php" method="get" style='float: right;'>
1073 <p class="search-box" style='margin-left: 5px; float: left;'>
1074 <input type="search" name="s" style="width: 120px;" value="<?php echo $s ? $s : ""; ?>">
1075 <input type="hidden" name="page" value="media-cleaner">
1076 <input type="hidden" name="view" value="<?php echo $view; ?>">
1077 <input type="hidden" name="paged" value="<?php echo $paged; ?>">
1078 <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>
1079 </p>
1080 </form>
1081
1082 <!-- PROGRESS -->
1083 <span style='margin-left: 12px; font-size: 15px; top: 5px; position: relative; color: #747474;' id='wpmc_progression'></span>
1084
1085 </div>
1086
1087 <p>
1088 <?php
1089 $method = get_option( 'wpmc_method', 'media' );
1090 if ( !$this->admin->is_registered() )
1091 $method = 'media';
1092
1093 $hide_warning = get_option( 'wpmc_hide_warning', false );
1094
1095 if ( !$hide_warning ) {
1096 _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' );
1097 }
1098
1099 if ( !MEDIA_TRASH ) {
1100 _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>" );
1101 }
1102
1103 if ( !$this->admin->is_registered() ) {
1104 echo "<div class='notice notice-info'><p>";
1105 _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' );
1106 echo "</p></div>";
1107 }
1108
1109 $anychecks = get_option( 'wpmc_posts', true ) || get_option(' wpmc_galleries', false ) ||
1110 get_option(' wpmc_postmeta', true );
1111 $check_library = get_option(' wpmc_media_library', false );
1112
1113 if ( $method == 'media' ) {
1114 if ( !$anychecks )
1115 _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' );
1116 else
1117 _e( "<div class='notice notice-success'><p>Media Cleaner will analyze your Media Library.</p></div>", 'media-cleaner' );
1118 }
1119 else if ( $method == 'files' ) {
1120 if ( !$anychecks && !$check_library )
1121 _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' );
1122 else
1123 _e( "<div class='notice notice-success'><p>Media Cleaner will analyze your Filesystem.</p></div>", 'media-cleaner' );
1124 }
1125
1126 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 ) );
1127 ?>
1128 </p>
1129
1130 <div id='wpmc-pages'>
1131 <?php
1132 echo paginate_links(array(
1133 'base' => '?page=media-cleaner&s=' . urlencode($s) . '&view=' . $view . '%_%',
1134 'current' => $paged,
1135 'format' => '&paged=%#%',
1136 'total' => ceil( $items_count / $posts_per_page ),
1137 'prev_next' => false
1138 ));
1139 ?>
1140 </div>
1141
1142 <ul class="subsubsub">
1143 <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> |
1144 <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> |
1145 <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>
1146 </ul>
1147
1148 <table id='wpmc-table' class='wp-list-table widefat fixed media'>
1149
1150 <thead>
1151 <tr>
1152 <th scope="col" id="cb" class="manage-column column-cb check-column"><input id="wpmc-cb-select-all" type="checkbox"></th>
1153 <?php if ( !get_option( 'wpmc_hide_thumbnails', false ) ): ?>
1154 <th style='width: 64px;'><?php _e( 'Thumb', 'media-cleaner' ) ?></th>
1155 <?php endif; ?>
1156 <th style='width: 50px;'><?php _e( 'Type', 'media-cleaner' ) ?></th>
1157 <th style='width: 80px;'><?php _e( 'Origin', 'media-cleaner' ) ?></th>
1158
1159 <?php if ( !empty( $wplr ) ): ?>
1160 <th style='width: 70px;'><?php _e( 'LR ID', 'media-cleaner' ) ?></th>
1161 <?php endif; ?>
1162
1163 <th><?php _e( 'Path', 'media-cleaner' ) ?></th>
1164 <th style='width: 220px;'><?php _e( 'Issue', 'media-cleaner' ) ?></th>
1165 <th style='width: 80px; text-align: right;'><?php _e( 'Size', 'media-cleaner' ) ?></th>
1166 </tr>
1167 </thead>
1168
1169 <tbody>
1170 <?php
1171 foreach ( $items as $issue ) {
1172 $regex = "^(.*)(\\s\\(\\+.*)$";
1173 $issue->path = preg_replace( '/' .$regex . '/i', '$1', $issue->path );
1174 ?>
1175 <tr>
1176 <td><input type="checkbox" name="id" value="<?php echo $issue->id ?>"></td>
1177 <?php if ( !get_option( 'wpmc_hide_thumbnails', false ) ): ?>
1178 <td>
1179 <?php
1180 if ( $issue->deleted == 0 ) {
1181 if ( $issue ->type == 0 ) {
1182 // FILE
1183 $upload_dir = wp_upload_dir();
1184 $url = htmlspecialchars( $upload_dir['baseurl'] . '/' . $issue->path, ENT_QUOTES );
1185 echo "<a target='_blank' href='" . $url .
1186 "'><img style='max-width: 48px; max-height: 48px;' src='" . $url . "' /></a>";
1187 }
1188 else {
1189 // MEDIA
1190 $attachmentsrc = wp_get_attachment_image_src( $issue->postId, 'thumbnail' );
1191 $attachmentsrc_clean = htmlspecialchars( $attachmentsrc[0], ENT_QUOTES );
1192 echo "<a target='_blank' href='" . $attachmentsrc_clean .
1193 "'><img style='max-width: 48px; max-height: 48px;' src='" .
1194 $attachmentsrc_clean . "' />";
1195 }
1196 }
1197 if ( $issue->deleted == 1 ) {
1198 $upload_dir = wp_upload_dir();
1199 $url = htmlspecialchars( $upload_dir['baseurl'] . '/wpmc-trash/' . $issue->path, ENT_QUOTES );
1200 echo "<a target='_blank' href='" . $url .
1201 "'><img style='max-width: 48px; max-height: 48px;' src='" . $url . "' /></a>";
1202 }
1203 ?>
1204 </td>
1205 <?php endif; ?>
1206 <td><?php echo $issue->type == 0 ? 'FILE' : 'MEDIA'; ?></td>
1207 <td><?php echo $issue->type == 0 ? 'Filesystem' : ("<a href='post.php?post=" .
1208 $issue->postId . "&action=edit'>ID " . $issue->postId . "</a>"); ?></td>
1209 <?php if ( !empty( $wplr ) ) { $info = $wplr->get_sync_info( $issue->postId ); ?>
1210 <td style='width: 70px;'><?php echo ( !empty( $info ) && $info->lr_id ? $info->lr_id : "" ); ?></td>
1211 <?php } ?>
1212 <td><?php echo stripslashes( $issue->path ); ?></td>
1213 <td><?php $this->echo_issue( $issue->issue ); ?></td>
1214 <td style='text-align: right;'><?php echo number_format( $issue->size / 1000, 2 ); ?> KB</td>
1215 </tr>
1216 <?php } ?>
1217 </tbody>
1218
1219 <tfoot>
1220 <tr><th></th>
1221 <?php if ( !get_option( 'hide_thumbnails', false ) ): ?>
1222 <th></th>
1223 <?php endif; ?>
1224 <th><?php _e( 'Type', 'media-cleaner' ) ?></th><th><?php _e( 'Origin', 'media-cleaner' ) ?></th>
1225 <?php if ( !empty( $wplr ) ): ?>
1226 <th style='width: 70px;'><?php _e( 'LR ID', 'media-cleaner' ) ?></th>
1227 <?php endif; ?>
1228 <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>
1229 </tfoot>
1230
1231 </table>
1232 </wrap>
1233
1234 <?php
1235 }
1236
1237 function admin_menu() {
1238 //load_plugin_textdomain( 'media-cleaner', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
1239 add_media_page( 'Media Cleaner', 'Cleaner', 'manage_options', 'media-cleaner', array( $this, 'wpmc_screen' ) );
1240 }
1241
1242 function wp_enqueue_scripts () {
1243 wp_enqueue_style( 'media-cleaner-css', plugins_url( '/media-cleaner.css', __FILE__ ) );
1244 wp_enqueue_script( 'media-cleaner', plugins_url( '/media-cleaner.js', __FILE__ ), array( 'jquery' ), "3.7.0", true );
1245 }
1246 }
1247
1248
1249 /*
1250 INSTALL / UNINSTALL
1251 */
1252
1253 register_activation_hook( __FILE__, 'wpmc_activate' );
1254 register_deactivation_hook( __FILE__, 'wpmc_uninstall' );
1255 register_uninstall_hook( __FILE__, 'wpmc_uninstall' );
1256
1257 function wpmc_reset() {
1258 wpmc_uninstall();
1259 wpmc_activate();
1260 }
1261
1262 function wpmc_activate () {
1263 global $wpdb;
1264 $table_name = $wpdb->prefix . "wpmcleaner";
1265 $charset_collate = $wpdb->get_charset_collate();
1266 $sql = "CREATE TABLE $table_name (
1267 id BIGINT(20) NOT NULL AUTO_INCREMENT,
1268 time DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL,
1269 type TINYINT(1) NOT NULL,
1270 postId BIGINT(20) NULL,
1271 path TINYTEXT NULL,
1272 size INT(9) NULL,
1273 ignored TINYINT(1) NOT NULL DEFAULT 0,
1274 deleted TINYINT(1) NOT NULL DEFAULT 0,
1275 issue TINYTEXT NOT NULL,
1276 UNIQUE KEY id (id)
1277 ) " . $charset_collate . ";";
1278 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
1279 dbDelta( $sql );
1280
1281 $upload_folder = wp_upload_dir();
1282 $basedir = $upload_folder['basedir'];
1283 if ( !is_writable( $basedir ) ) {
1284 echo '<div class="error"><p>' . __( 'The directory for uploads is not writable. Media Cleaner will only be able to scan.', 'media-cleaner' ) . '</p></div>';
1285 }
1286 }
1287
1288 function wpmc_uninstall () {
1289 global $wpdb;
1290 $table_name = $wpdb->prefix . "wpmcleaner";
1291 $wpdb->query("DROP TABLE IF EXISTS $table_name");
1292 }
1293