Media Cleaner - Version 5.2.4

Version Description

  • Add: Lot of refactoring and optimizations.
  • Add: Support for Theme X, ZipList, and better support for standard websites as well.
  • Add: Yes/No dialog for Reset button.
Download this release

Release Info

Developer TigrouMeow
Plugin Icon 128x128 Media Cleaner
Version 5.2.4
Comparing to
See all releases

Code changes from version 5.2.1 to 5.2.4

admin.php CHANGED
@@ -61,8 +61,8 @@ class Meow_WPMC_Admin extends MeowApps_Admin {
61
  update_option( 'wpmc_delay', 100 );
62
 
63
  if ( !$this->is_registered() && get_option( 'wpmc_method', 'media' ) == 'files' ) {
64
- _e( "<div class='error'><p>The Pro version is required to scan files. You can <a target='_blank' href='http://meowapps.com/media-cleaner'>get a serial for the Pro version here</a>.</p></div>", 'media-cleaner' );
65
- }
66
  }
67
 
68
  function common_url( $file ) {
@@ -176,32 +176,32 @@ class Meow_WPMC_Admin extends MeowApps_Admin {
176
  }
177
 
178
  function admin_medias_buffer_callback( $args ) {
179
- $value = get_option( 'wpmc_medias_buffer', 100 );
180
- $html = '<input type="number" style="width: 100%;" id="wpmc_medias_buffer" name="wpmc_medias_buffer" value="' . $value . '" />';
181
- $html .= '<br /><span class="description">The number of media entries to read at a time. This is fast, so the value should be between 50 and 1000.</label>';
182
- echo $html;
183
- }
184
 
185
  function admin_posts_buffer_callback( $args ) {
186
- $value = get_option( 'wpmc_posts_buffer', 5 );
187
- $html = '<input type="number" style="width: 100%;" id="wpmc_posts_buffer" name="wpmc_posts_buffer" value="' . $value . '" />';
188
- $html .= '<br /><span class="description">The number of posts (and any other post types) to analyze at a time. This is the most intense part of the process. Recommended value is between 1 (slow server) and 20 (excellent server).</label>';
189
- echo $html;
190
- }
191
 
192
  function admin_analysis_buffer_callback( $args ) {
193
- $value = get_option( 'wpmc_analysis_buffer', 100 );
194
- $html = '<input type="number" style="width: 100%;" id="wpmc_analysis_buffer" name="wpmc_analysis_buffer" value="' . $value . '" />';
195
- $html .= '<br /><span class="description">The number of media entries or files to analyze at a time. This is the main part of the process, but is is much faster than analyzing each post. Recommended value is between 20 (slow server) and 1000 (excellent server).</label>';
196
- echo $html;
197
- }
198
 
199
  function admin_delay_callback( $args ) {
200
- $value = get_option( 'wpmc_delay', 100 );
201
- $html = '<input type="number" style="width: 100%;" id="wpmc_delay" name="wpmc_delay" value="' . $value . '" />';
202
- $html .= '<br /><span class="description">Time to wait between each request (in milliseconds). The overall process is intensive so this gives the chance to your server to chill out a bit. A very good server doesn\'t need it, but a slow/shared hosting might even reject requests if they are too fast and frequent. Recommended value is actually 0, 100 for safety, 2000 or 5000 if your hosting is kind of cheap.</label>';
203
- echo $html;
204
- }
205
 
206
  function admin_settings() {
207
  ?>
@@ -230,8 +230,8 @@ class Meow_WPMC_Admin extends MeowApps_Admin {
230
  <div class="inside">
231
  <form method="post" action="options.php">
232
  <?php settings_fields( 'wpmc_settings' ); ?>
233
- <?php do_settings_sections( 'wpmc_settings-menu' ); ?>
234
- <?php submit_button(); ?>
235
  </form>
236
  </div>
237
  </div>
@@ -241,8 +241,8 @@ class Meow_WPMC_Admin extends MeowApps_Admin {
241
  <div class="inside">
242
  <form method="post" action="options.php">
243
  <?php settings_fields( 'wpmc_filters_settings' ); ?>
244
- <?php do_settings_sections( 'wpmc_filters_settings-menu' ); ?>
245
- <?php submit_button(); ?>
246
  </form>
247
  </div>
248
 
@@ -258,8 +258,8 @@ class Meow_WPMC_Admin extends MeowApps_Admin {
258
  <div class="inside">
259
  <form method="post" action="options.php">
260
  <?php settings_fields( 'wpmc_ui_settings' ); ?>
261
- <?php do_settings_sections( 'wpmc_ui_settings-menu' ); ?>
262
- <?php submit_button(); ?>
263
  </form>
264
  </div>
265
  </div>
@@ -269,8 +269,8 @@ class Meow_WPMC_Admin extends MeowApps_Admin {
269
  <div class="inside">
270
  <form method="post" action="options.php">
271
  <?php settings_fields( 'wpmc_advanced_settings' ); ?>
272
- <?php do_settings_sections( 'wpmc_advanced_settings-menu' ); ?>
273
- <?php submit_button(); ?>
274
  </form>
275
  </div>
276
  </div>
@@ -283,20 +283,20 @@ class Meow_WPMC_Admin extends MeowApps_Admin {
283
  <p>Here are the shortcodes registered in your WordPress by your theme and other plugins.</p>
284
  <?php
285
  global $shortcode_tags;
286
- try {
287
  if ( is_array( $shortcode_tags ) ) {
288
- $my_shortcodes = array();
289
- foreach ( $shortcode_tags as $sc )
290
- if ( $sc != '__return_false' ) {
291
- if ( is_string( $sc ) )
292
- array_push( $my_shortcodes, str_replace( '_shortcode', '', (string)$sc ) );
293
- }
294
- $my_shortcodes = implode( ', ', $my_shortcodes );
295
  }
296
- }
297
- catch (Exception $e) {
298
- $my_shortcodes = "";
299
- }
300
  echo $my_shortcodes;
301
  ?>
302
  </small></div>
@@ -318,30 +318,34 @@ class Meow_WPMC_Admin extends MeowApps_Admin {
318
  */
319
 
320
  function admin_method_callback( $args ) {
321
- $value = get_option( 'wpmc_method', 'media' );
322
  $html = '<select id="wpmc_method" name="wpmc_method">
323
- <option ' . selected( 'media', $value, false ) . 'value="media">Media Library</option>
324
- <option ' . disabled( $this->is_registered(), false, false ) . ' ' . selected( 'files', $value, false ) . 'value="files">Filesystem (Pro)</option>
325
  </select><small><br />' . __( 'Check the <a target="_blank" href="//meowapps.com/media-cleaner/tutorial/">tutorial</a> for more information.', 'media-cleaner' ) . '</small>';
326
- echo $html;
327
- }
 
 
 
 
328
 
329
 
330
  // function admin_shortcode_callback( $args ) {
331
- // $value = get_option( 'wpmc_shortcode', null );
332
  // $html = '<input ' . disabled( $this->is_registered(), false, false ) . ' type="checkbox" id="wpmc_shortcode" name="wpmc_shortcode" value="1" ' .
333
  // checked( 1, get_option( 'wpmc_shortcode' ), false ) . '/>';
334
- // $html .= '<label>Resolve</label><br /><small>The shortcodes you are using in your <b>posts</b> and/or <b>widgets</b> (depending on your options) will be resolved and analyzed. You don\'t need to have this option enabled for the WP Gallery (as it is covered by the Galleries option).</small>';
335
- // echo $html;
336
- // }
337
 
338
  // function admin_background_callback( $args ) {
339
- // $value = get_option( 'wpmc_background', null );
340
  // $html = '<input ' . disabled( $this->is_registered(), false, false ) . ' type="checkbox" id="wpmc_background" name="wpmc_background" value="1" ' .
341
  // checked( 1, get_option( 'wpmc_background' ), false ) . '/>';
342
- // $html .= '<label>Analyze</label><br /><small>When parsing HTML, the CSS inline background will also be analyzed. A few page builders are using this.</small>';
343
- // echo $html;
344
- // }
345
 
346
  function admin_debuglogs_callback( $args ) {
347
  global $wpmc;
@@ -367,52 +371,52 @@ class Meow_WPMC_Admin extends MeowApps_Admin {
367
  }
368
 
369
  function admin_media_library_callback( $args ) {
370
- $value = get_option( 'wpmc_media_library', true );
371
  $html = '<input type="checkbox" id="wpmc_media_library" name="wpmc_media_library" value="1" ' .
372
  disabled( get_option( 'wpmc_method', 'media' ) == 'files', false, false ) . ' ' .
373
  checked( 1, get_option( 'wpmc_media_library' ), false ) . '/>';
374
- $html .= '<label>Check</label><br /><small>Checks if the file is linked to a media. Only makes sense with the Filesystem scan.</small>';
375
- echo $html;
376
- }
377
 
378
  function admin_posts_callback( $args ) {
379
- $value = get_option( 'wpmc_posts', true );
380
  $html = '<input type="checkbox" id="wpmc_posts" name="wpmc_posts" value="1" ' .
381
  checked( 1, get_option( 'wpmc_posts' ), false ) . '/>';
382
- $html .= '<label>Analyze</label><br /><small>Check if the media/file is used by any post types.</small>';
383
- echo $html;
384
- }
385
 
386
  function admin_postmeta_callback( $args ) {
387
- $value = get_option( 'wpmc_postmeta', true );
388
  $html = '<input type="checkbox" id="wpmc_postmeta" name="wpmc_postmeta" value="1" ' .
389
  checked( 1, get_option( 'wpmc_postmeta' ), false ) . '/>';
390
- $html .= '<label>Analyze</label><br /><small>Checks if the media/file is used in the meta.</small>';
391
- echo $html;
392
- }
393
 
394
  function admin_widgets_callback( $args ) {
395
- $value = get_option( 'wpmc_widgets', false );
396
  $html = '<input type="checkbox" id="wpmc_widgets" name="wpmc_widgets" value="1" ' .
397
  checked( 1, get_option( 'wpmc_widgets' ), false ) . '/>';
398
- $html .= '<label>Analyze</label><br /><small>Checks if the media/file is used by any widget.</small>';
399
- echo $html;
400
- }
401
 
402
  function admin_hide_thumbnails_callback( $args ) {
403
- $value = get_option( 'wpmc_hide_thumbnails', null );
404
  $html = '<input type="checkbox" id="wpmc_hide_thumbnails" name="wpmc_hide_thumbnails" value="1" ' .
405
  checked( 1, get_option( 'wpmc_hide_thumbnails' ), false ) . '/>';
406
- $html .= '<label>Hide</label><br /><small>If you prefer not to see the thumbnails.</small>';
407
- echo $html;
408
- }
409
 
410
  function admin_hide_warning_callback( $args ) {
411
- $value = get_option( 'wpmc_hide_warning', null );
412
  $html = '<input type="checkbox" id="wpmc_hide_warning" name="wpmc_hide_warning" value="1" ' .
413
  checked( 1, get_option( 'wpmc_hide_warning' ), false ) . '/>';
414
- $html .= '<label>Hide</label><br /><small>Have you read it twice? If yes, hide it :)</small>';
415
- echo $html;
416
  }
417
 
418
  function admin_results_per_page( $args ) {
@@ -424,12 +428,12 @@ HTML;
424
  }
425
 
426
  function admin_thumbnails_only_callback( $args ) {
427
- $value = get_option( 'wpmc_thumbnails_only', false );
428
  $html = '<input type="checkbox" id="wpmc_thumbnails_only" name="wpmc_thumbnails_only" value="1" ' .
429
  disabled( get_option( 'wpmc_method', 'media' ) == 'files', false, false ) . ' ' .
430
  checked( 1, get_option( 'wpmc_thumbnails_only' ), false ) . '/>';
431
- $html .= '<label>Enable</label><br /><small>Restrict the filesystem scan to thumbnails (files containing the resolution). If none of the checks above are selected, you will get the list of all the thumbnails and be able to remove them.</small>';
432
- echo $html;
433
  }
434
 
435
  function admin_dirs_filter_callback( $args ) {
@@ -457,14 +461,14 @@ HTML;
457
  function old_getoption( $option, $section, $default = '' ) {
458
  $options = get_option( $section );
459
  if ( isset( $options[$option] ) ) {
460
- if ( $options[$option] == "off" ) {
461
- return false;
462
- }
463
- if ( $options[$option] == "on" ) {
464
- return true;
465
- }
466
  return $options[$option];
467
- }
468
  return $default;
469
  }
470
 
61
  update_option( 'wpmc_delay', 100 );
62
 
63
  if ( !$this->is_registered() && get_option( 'wpmc_method', 'media' ) == 'files' ) {
64
+ _e( "<div class='error'><p>The Pro version is required to scan files. You can <a target='_blank' href='http://meowapps.com/media-cleaner'>get a serial for the Pro version here</a>.</p></div>", 'media-cleaner' );
65
+ }
66
  }
67
 
68
  function common_url( $file ) {
176
  }
177
 
178
  function admin_medias_buffer_callback( $args ) {
179
+ $value = get_option( 'wpmc_medias_buffer', 100 );
180
+ $html = '<input type="number" style="width: 100%;" id="wpmc_medias_buffer" name="wpmc_medias_buffer" value="' . $value . '" />';
181
+ $html .= '<br /><span class="description">The number of media entries to read at a time. This is fast, so the value should be between 50 and 1000.</label>';
182
+ echo $html;
183
+ }
184
 
185
  function admin_posts_buffer_callback( $args ) {
186
+ $value = get_option( 'wpmc_posts_buffer', 5 );
187
+ $html = '<input type="number" style="width: 100%;" id="wpmc_posts_buffer" name="wpmc_posts_buffer" value="' . $value . '" />';
188
+ $html .= '<br /><span class="description">The number of posts (and any other post types) to analyze at a time. This is the most intense part of the process. Recommended value is between 1 (slow server) and 20 (excellent server).</label>';
189
+ echo $html;
190
+ }
191
 
192
  function admin_analysis_buffer_callback( $args ) {
193
+ $value = get_option( 'wpmc_analysis_buffer', 100 );
194
+ $html = '<input type="number" style="width: 100%;" id="wpmc_analysis_buffer" name="wpmc_analysis_buffer" value="' . $value . '" />';
195
+ $html .= '<br /><span class="description">The number of media entries or files to analyze at a time. This is the main part of the process, but is is much faster than analyzing each post. Recommended value is between 20 (slow server) and 1000 (excellent server).</label>';
196
+ echo $html;
197
+ }
198
 
199
  function admin_delay_callback( $args ) {
200
+ $value = get_option( 'wpmc_delay', 100 );
201
+ $html = '<input type="number" style="width: 100%;" id="wpmc_delay" name="wpmc_delay" value="' . $value . '" />';
202
+ $html .= '<br /><span class="description">Time to wait between each request (in milliseconds). The overall process is intensive so this gives the chance to your server to chill out a bit. A very good server doesn\'t need it, but a slow/shared hosting might even reject requests if they are too fast and frequent. Recommended value is actually 0, 100 for safety, 2000 or 5000 if your hosting is kind of cheap.</label>';
203
+ echo $html;
204
+ }
205
 
206
  function admin_settings() {
207
  ?>
230
  <div class="inside">
231
  <form method="post" action="options.php">
232
  <?php settings_fields( 'wpmc_settings' ); ?>
233
+ <?php do_settings_sections( 'wpmc_settings-menu' ); ?>
234
+ <?php submit_button(); ?>
235
  </form>
236
  </div>
237
  </div>
241
  <div class="inside">
242
  <form method="post" action="options.php">
243
  <?php settings_fields( 'wpmc_filters_settings' ); ?>
244
+ <?php do_settings_sections( 'wpmc_filters_settings-menu' ); ?>
245
+ <?php submit_button(); ?>
246
  </form>
247
  </div>
248
 
258
  <div class="inside">
259
  <form method="post" action="options.php">
260
  <?php settings_fields( 'wpmc_ui_settings' ); ?>
261
+ <?php do_settings_sections( 'wpmc_ui_settings-menu' ); ?>
262
+ <?php submit_button(); ?>
263
  </form>
264
  </div>
265
  </div>
269
  <div class="inside">
270
  <form method="post" action="options.php">
271
  <?php settings_fields( 'wpmc_advanced_settings' ); ?>
272
+ <?php do_settings_sections( 'wpmc_advanced_settings-menu' ); ?>
273
+ <?php submit_button(); ?>
274
  </form>
275
  </div>
276
  </div>
283
  <p>Here are the shortcodes registered in your WordPress by your theme and other plugins.</p>
284
  <?php
285
  global $shortcode_tags;
286
+ try {
287
  if ( is_array( $shortcode_tags ) ) {
288
+ $my_shortcodes = array();
289
+ foreach ( $shortcode_tags as $sc )
290
+ if ( $sc != '__return_false' ) {
291
+ if ( is_string( $sc ) )
292
+ array_push( $my_shortcodes, str_replace( '_shortcode', '', (string)$sc ) );
293
+ }
294
+ $my_shortcodes = implode( ', ', $my_shortcodes );
295
  }
296
+ }
297
+ catch (Exception $e) {
298
+ $my_shortcodes = "";
299
+ }
300
  echo $my_shortcodes;
301
  ?>
302
  </small></div>
318
  */
319
 
320
  function admin_method_callback( $args ) {
321
+ $value = get_option( 'wpmc_method', 'media' );
322
  $html = '<select id="wpmc_method" name="wpmc_method">
323
+ <option ' . selected( 'media', $value, false ) . 'value="media">Media Library</option>
324
+ <option ' . disabled( $this->is_registered(), false, false ) . ' ' . selected( 'files', $value, false ) . 'value="files">Filesystem (Pro)</option>
325
  </select><small><br />' . __( 'Check the <a target="_blank" href="//meowapps.com/media-cleaner/tutorial/">tutorial</a> for more information.', 'media-cleaner' ) . '</small>';
326
+
327
+ // TODO: This is temporary
328
+ $html .= '<br /><br /><small><b style="color: red;">Notice: </b><b> Those settings will be simplified soon. Have a look <a href="https://trello.com/c/qrCuITg8/55-cleaner-simplification-of-the-settings" target="_blank">here</a> and let me know in the comments if you like the idea or not.</b></small>';
329
+
330
+ echo $html;
331
+ }
332
 
333
 
334
  // function admin_shortcode_callback( $args ) {
335
+ // $value = get_option( 'wpmc_shortcode', null );
336
  // $html = '<input ' . disabled( $this->is_registered(), false, false ) . ' type="checkbox" id="wpmc_shortcode" name="wpmc_shortcode" value="1" ' .
337
  // checked( 1, get_option( 'wpmc_shortcode' ), false ) . '/>';
338
+ // $html .= '<label>Resolve</label><br /><small>The shortcodes you are using in your <b>posts</b> and/or <b>widgets</b> (depending on your options) will be resolved and analyzed. You don\'t need to have this option enabled for the WP Gallery (as it is covered by the Galleries option).</small>';
339
+ // echo $html;
340
+ // }
341
 
342
  // function admin_background_callback( $args ) {
343
+ // $value = get_option( 'wpmc_background', null );
344
  // $html = '<input ' . disabled( $this->is_registered(), false, false ) . ' type="checkbox" id="wpmc_background" name="wpmc_background" value="1" ' .
345
  // checked( 1, get_option( 'wpmc_background' ), false ) . '/>';
346
+ // $html .= '<label>Analyze</label><br /><small>When parsing HTML, the CSS inline background will also be analyzed. A few page builders are using this.</small>';
347
+ // echo $html;
348
+ // }
349
 
350
  function admin_debuglogs_callback( $args ) {
351
  global $wpmc;
371
  }
372
 
373
  function admin_media_library_callback( $args ) {
374
+ $value = get_option( 'wpmc_media_library', true );
375
  $html = '<input type="checkbox" id="wpmc_media_library" name="wpmc_media_library" value="1" ' .
376
  disabled( get_option( 'wpmc_method', 'media' ) == 'files', false, false ) . ' ' .
377
  checked( 1, get_option( 'wpmc_media_library' ), false ) . '/>';
378
+ $html .= '<label>Check</label><br /><small>Checks if the file is linked to a media. Only makes sense with the Filesystem scan.</small>';
379
+ echo $html;
380
+ }
381
 
382
  function admin_posts_callback( $args ) {
383
+ $value = get_option( 'wpmc_posts', true );
384
  $html = '<input type="checkbox" id="wpmc_posts" name="wpmc_posts" value="1" ' .
385
  checked( 1, get_option( 'wpmc_posts' ), false ) . '/>';
386
+ $html .= '<label>Analyze</label><br /><small>Check if the media/file is used by any post types.</small>';
387
+ echo $html;
388
+ }
389
 
390
  function admin_postmeta_callback( $args ) {
391
+ $value = get_option( 'wpmc_postmeta', true );
392
  $html = '<input type="checkbox" id="wpmc_postmeta" name="wpmc_postmeta" value="1" ' .
393
  checked( 1, get_option( 'wpmc_postmeta' ), false ) . '/>';
394
+ $html .= '<label>Analyze</label><br /><small>Checks if the media/file is used in the meta.</small>';
395
+ echo $html;
396
+ }
397
 
398
  function admin_widgets_callback( $args ) {
399
+ $value = get_option( 'wpmc_widgets', false );
400
  $html = '<input type="checkbox" id="wpmc_widgets" name="wpmc_widgets" value="1" ' .
401
  checked( 1, get_option( 'wpmc_widgets' ), false ) . '/>';
402
+ $html .= '<label>Analyze</label><br /><small>Checks if the media/file is used by any widget.</small>';
403
+ echo $html;
404
+ }
405
 
406
  function admin_hide_thumbnails_callback( $args ) {
407
+ $value = get_option( 'wpmc_hide_thumbnails', null );
408
  $html = '<input type="checkbox" id="wpmc_hide_thumbnails" name="wpmc_hide_thumbnails" value="1" ' .
409
  checked( 1, get_option( 'wpmc_hide_thumbnails' ), false ) . '/>';
410
+ $html .= '<label>Hide</label><br /><small>If you prefer not to see the thumbnails.</small>';
411
+ echo $html;
412
+ }
413
 
414
  function admin_hide_warning_callback( $args ) {
415
+ $value = get_option( 'wpmc_hide_warning', null );
416
  $html = '<input type="checkbox" id="wpmc_hide_warning" name="wpmc_hide_warning" value="1" ' .
417
  checked( 1, get_option( 'wpmc_hide_warning' ), false ) . '/>';
418
+ $html .= '<label>Hide</label><br /><small>Have you read it twice? If yes, hide it :)</small>';
419
+ echo $html;
420
  }
421
 
422
  function admin_results_per_page( $args ) {
428
  }
429
 
430
  function admin_thumbnails_only_callback( $args ) {
431
+ $value = get_option( 'wpmc_thumbnails_only', false );
432
  $html = '<input type="checkbox" id="wpmc_thumbnails_only" name="wpmc_thumbnails_only" value="1" ' .
433
  disabled( get_option( 'wpmc_method', 'media' ) == 'files', false, false ) . ' ' .
434
  checked( 1, get_option( 'wpmc_thumbnails_only' ), false ) . '/>';
435
+ $html .= '<label>Enable</label><br /><small>Restrict the filesystem scan to thumbnails (files containing the resolution). If none of the checks above are selected, you will get the list of all the thumbnails and be able to remove them.</small>';
436
+ echo $html;
437
  }
438
 
439
  function admin_dirs_filter_callback( $args ) {
461
  function old_getoption( $option, $section, $default = '' ) {
462
  $options = get_option( $section );
463
  if ( isset( $options[$option] ) ) {
464
+ if ( $options[$option] == "off" ) {
465
+ return false;
466
+ }
467
+ if ( $options[$option] == "on" ) {
468
+ return true;
469
+ }
470
  return $options[$option];
471
+ }
472
  return $default;
473
  }
474
 
api.php CHANGED
@@ -2,8 +2,9 @@
2
 
3
  class Meow_WPMC_API {
4
 
5
- function __construct( $core, $admin ) {
6
  $this->core = $core;
 
7
  $this->admin = $admin;
8
  add_action( 'wp_ajax_wpmc_prepare_do', array( $this, 'wp_ajax_wpmc_prepare_do' ) );
9
  add_action( 'wp_ajax_wpmc_scan', array( $this, 'wp_ajax_wpmc_scan' ) );
@@ -23,131 +24,13 @@ class Meow_WPMC_API {
23
  function wp_ajax_wpmc_prepare_do() {
24
  $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
25
  $limitsize = get_option( 'wpmc_posts_buffer', 5 );
26
- if ( empty( $limit ) )
27
- $this->core->reset_issues();
28
-
29
- $method = get_option( 'wpmc_method', 'media' );
30
- $check_library = get_option(' wpmc_media_library', true );
31
- $check_postmeta = get_option( 'wpmc_postmeta', false );
32
- $check_posts = get_option( 'wpmc_posts', false );
33
- $check_widgets = get_option( 'wpmc_widgets', false );
34
- if ( $method == 'media' && !$check_posts && !$check_postmeta && !$check_widgets ) {
35
- echo json_encode( array(
36
- 'results' => array(),
37
- 'success' => true,
38
- 'finished' => true,
39
- 'message' => __( "Posts, Meta and Widgets analysis are all off. Done.", 'media-cleaner' )
40
- ) );
41
- die();
42
- }
43
- if ( $method == 'files' && $check_library && !$check_posts && !$check_postmeta && !$check_widgets ) {
44
- echo json_encode( array(
45
- 'results' => array(),
46
- 'success' => true,
47
- 'finished' => true,
48
- 'message' => __( "Posts, Meta and Widgets analysis are all off. Done.", 'media-cleaner' )
49
- ) );
50
- die();
51
- }
52
-
53
- // Initialize the parsers
54
- do_action( 'wpmc_initialize_parsers' );
55
-
56
- global $wpdb;
57
- // Maybe we could avoid to check more post_types.
58
- // SELECT post_type, COUNT(*) FROM `wp_posts` GROUP BY post_type
59
- $posts = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
60
- WHERE p.post_status != 'inherit'
61
- AND p.post_status != 'trash'
62
- AND p.post_type != 'attachment'
63
- AND p.post_type != 'shop_order'
64
- AND p.post_type != 'shop_order_refund'
65
- AND p.post_type != 'nav_menu_item'
66
- AND p.post_type != 'revision'
67
- AND p.post_type != 'auto-draft'
68
- AND p.post_type != 'wphb_minify_group'
69
- AND p.post_type != 'customize_changeset'
70
- AND p.post_type != 'oembed_cache'
71
- AND p.post_type NOT LIKE '%acf-%'
72
- AND p.post_type NOT LIKE '%edd_%'
73
- LIMIT %d, %d", $limit, $limitsize
74
- )
75
- );
76
-
77
- $found = array();
78
-
79
- // Only at the beginning
80
- if ( empty( $limit ) ) {
81
- $this->core->log( "Parsed references:" );
82
- if ( get_option( 'wpmc_widgets', false ) ) {
83
-
84
- global $wp_registered_widgets;
85
- $syswidgets = $wp_registered_widgets;
86
- $active_widgets = get_option( 'sidebars_widgets' );
87
- foreach ( $active_widgets as $sidebar_name => $widgets ) {
88
- if ( $sidebar_name != 'wp_inactive_widgets' && !empty( $widgets ) && is_array( $widgets ) ) {
89
- foreach ( $widgets as $key => $widget ) {
90
- do_action( 'wpmc_scan_widget', $syswidgets[$widget] );
91
- }
92
- }
93
- }
94
-
95
- do_action( 'wpmc_scan_widgets' );
96
- }
97
- do_action( 'wpmc_scan_once' );
98
- }
99
-
100
- $this->core->timeout_check_start( count( $posts ) );
101
-
102
- foreach ( $posts as $post ) {
103
- $this->core->timeout_check();
104
- // Run the scanners
105
- if ( $check_postmeta )
106
- do_action( 'wpmc_scan_postmeta', $post );
107
- if ( $check_posts ) {
108
- // Get HTML for this post
109
- $html = get_post_field( 'post_content', $post );
110
-
111
- // Scan on the raw HTML content (useless?)
112
- //do_action( 'wpmc_scan_post', $html, $post );
113
-
114
- // This code was moved to the core.php (get_urls_from_html)
115
- //$html = do_shortcode( $html );
116
- //$html = wp_make_content_images_responsive( $html );
117
- // Scan with shortcodes resolved and src-set
118
-
119
- do_action( 'wpmc_scan_post', $html, $post );
120
- }
121
- $this->core->timeout_check_additem();
122
- }
123
-
124
- // Write the references cached by the scanners
125
- $this->core->write_references();
126
-
127
- $finished = count( $posts ) < $limitsize;
128
- if ( $finished ) {
129
- $this->core->log();
130
- $found = array();
131
- // Optimize DB (but that takes too long!)
132
- //$table_name = $wpdb->prefix . "mclean_refs";
133
- // $wpdb->query ("DELETE a FROM $table_name as a, $table_name as b
134
- // WHERE (a.mediaId = b.mediaId OR a.mediaId IS NULL AND b.mediaId IS NULL)
135
- // AND (a.mediaUrl = b.mediaUrl OR a.mediaUrl IS NULL AND b.mediaUrl IS NULL)
136
- // AND (a.originType = b.originType OR a.originType IS NULL AND b.originType IS NULL)
137
- // AND (a.origin = b.origin OR a.origin IS NULL AND b.origin IS NULL)
138
- // AND a.ID < b.ID;" );
139
- // $wpdb->query ("DELETE a FROM $table_name as a, $table_name as b WHERE a.mediaId = b.mediaId AND a.mediaId > 0 AND a.ID < b.ID;" );
140
- // $wpdb->query ("DELETE a FROM $table_name as a, $table_name as b WHERE a.mediaUrl = b.mediaUrl AND LENGTH(a.mediaUrl) > 1 AND a.ID < b.ID;" );
141
- }
142
- if ( $finished && get_option( 'wpmc_debuglogs', false ) ) {
143
- //$this->core->log( print_r( $found, true ) );
144
- }
145
  echo json_encode(
146
  array(
147
  'success' => true,
148
  'finished' => $finished,
149
  'limit' => $limit + $limitsize,
150
- 'message' => __( "Posts checked.", 'media-cleaner' ) )
151
  );
152
  die();
153
  }
@@ -158,26 +41,34 @@ class Meow_WPMC_API {
158
  $method = get_option( 'wpmc_method', 'media' );
159
  if ( !$this->admin->is_registered() )
160
  $method = 'media';
161
- $path = isset( $_POST['path'] ) ? $_POST['path'] : null;
162
- $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
163
- $limitsize = get_option( 'wpmc_medias_buffer', 100 );
164
 
165
  if ( $method == 'files' ) {
166
- $output = apply_filters( 'wpmc_list_uploaded_files', array(
167
- 'results' => array(), 'success' => false, 'message' => __( "Unavailable.", 'media-cleaner' )
168
- ), $path );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  echo json_encode( $output );
170
  die();
171
  }
172
 
173
  if ( $method == 'media' ) {
174
- // Prevent double scanning by removing filesystem entries that we have DB entries for
175
- $results = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
176
- WHERE p.post_status = 'inherit'
177
- AND p.post_type = 'attachment'
178
- LIMIT %d, %d", $limit, $limitsize
179
- )
180
- );
181
  $finished = count( $results ) < $limitsize;
182
  echo json_encode(
183
  array(
@@ -206,17 +97,22 @@ class Meow_WPMC_API {
206
  $data = $_POST['data'];
207
  $this->core->timeout_check_start( count( $data ) );
208
  $success = 0;
 
 
 
209
  foreach ( $data as $piece ) {
210
  $this->core->timeout_check();
211
  if ( $type == 'file' ) {
212
  $this->core->log( "Check File: {$piece}" );
213
- $result = ( apply_filters( 'wpmc_check_file', true, $piece ) ? 1 : 0 );
 
 
214
  if ( $result )
215
  $success += $result;
216
  }
217
  else if ( $type == 'media' ) {
218
  $this->core->log( "Checking Media #{$piece}" );
219
- $result = ( $this->core->check_media( $piece ) ? 1 : 0 );
220
  if ( $result )
221
  $success += $result;
222
  }
2
 
3
  class Meow_WPMC_API {
4
 
5
+ function __construct( $core, $admin, $engine ) {
6
  $this->core = $core;
7
+ $this->engine = $engine;
8
  $this->admin = $admin;
9
  add_action( 'wp_ajax_wpmc_prepare_do', array( $this, 'wp_ajax_wpmc_prepare_do' ) );
10
  add_action( 'wp_ajax_wpmc_scan', array( $this, 'wp_ajax_wpmc_scan' ) );
24
  function wp_ajax_wpmc_prepare_do() {
25
  $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
26
  $limitsize = get_option( 'wpmc_posts_buffer', 5 );
27
+ $finished = $this->engine->parse( $limit, $limitsize, $message ); // $message is set by run()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  echo json_encode(
29
  array(
30
  'success' => true,
31
  'finished' => $finished,
32
  'limit' => $limit + $limitsize,
33
+ 'message' => $message )
34
  );
35
  die();
36
  }
41
  $method = get_option( 'wpmc_method', 'media' );
42
  if ( !$this->admin->is_registered() )
43
  $method = 'media';
 
 
 
44
 
45
  if ( $method == 'files' ) {
46
+ $output = null;
47
+ $path = isset( $_POST['path'] ) ? $_POST['path'] : null;
48
+ $files = $this->engine->get_files( $path );
49
+
50
+ if ( $files === null ) {
51
+ $output = array(
52
+ 'results' => array(),
53
+ 'success' => false,
54
+ 'message' => __( "Unavailable.", 'media-cleaner' )
55
+ );
56
+ }
57
+ else {
58
+ $output = array(
59
+ 'results' => $files,
60
+ 'success' => true,
61
+ 'message' => __( "Files retrieved.", 'media-cleaner' )
62
+ );
63
+ }
64
  echo json_encode( $output );
65
  die();
66
  }
67
 
68
  if ( $method == 'media' ) {
69
+ $limit = isset( $_POST['limit'] ) ? $_POST['limit'] : 0;
70
+ $limitsize = get_option( 'wpmc_medias_buffer', 100 );
71
+ $results = $this->engine->get_media_entries( $limit, $limitsize );
 
 
 
 
72
  $finished = count( $results ) < $limitsize;
73
  echo json_encode(
74
  array(
97
  $data = $_POST['data'];
98
  $this->core->timeout_check_start( count( $data ) );
99
  $success = 0;
100
+ if ( $type == 'file' ) {
101
+ do_action( 'wpmc_check_file_init' ); // Build_CroppedFile_Cache() in pro core.php
102
+ }
103
  foreach ( $data as $piece ) {
104
  $this->core->timeout_check();
105
  if ( $type == 'file' ) {
106
  $this->core->log( "Check File: {$piece}" );
107
+
108
+ $result = ( $this->engine->check_file( $piece ) ? 1 : 0 );
109
+
110
  if ( $result )
111
  $success += $result;
112
  }
113
  else if ( $type == 'media' ) {
114
  $this->core->log( "Checking Media #{$piece}" );
115
+ $result = ( $this->engine->check_media( $piece ) ? 1 : 0 );
116
  if ( $result )
117
  $success += $result;
118
  }
core.php CHANGED
@@ -3,25 +3,41 @@
3
  class Meow_WPMC_Core {
4
 
5
  public $admin = null;
6
- public $last_analysis = null;
7
- public $last_analysis_ids = null;
8
- private $regex_file = '/[A-Za-z0-9-_,\s]+[.]{1}(MIMETYPES)/';
9
  public $current_method = 'media';
10
  private $refcache = array();
11
  public $servername = null;
12
  public $upload_folder = null;
13
  public $contentDir = null; // becomes 'wp-content/uploads'
 
 
 
 
 
14
 
15
  public function __construct( $admin ) {
16
  $this->admin = $admin;
17
- $site_url = get_site_url();
18
  $this->current_method = get_option( 'wpmc_method', 'media' );
19
  $types = "jpg|jpeg|jpe|gif|png|tiff|bmp|csv|pdf|xls|xlsx|doc|docx|tiff|mp3|mp4|wav|lua";
20
- $this->regex_file = str_replace( "MIMETYPES", $types, $this->regex_file );
21
- $this->servername = str_replace( 'http://', '', str_replace( 'https://', '', $site_url ) );
22
  $this->upload_folder = wp_upload_dir();
23
- $this->contentDir = substr( $this->upload_folder['baseurl'], 1 + strlen( $site_url ) );
 
 
 
 
24
  add_action( 'wpmc_initialize_parsers', array( $this, 'initialize_parsers' ), 10, 0 );
 
 
 
 
 
 
 
25
  }
26
 
27
  function initialize_parsers() {
@@ -109,26 +125,43 @@ class Meow_WPMC_Core {
109
  }
110
 
111
  function get_favicon() {
 
112
  $vals = get_option( 'wpseo_titles' );
113
- $url = $vals['company_logo'];
114
- if ( $this->is_url($url) )
115
- return $this->clean_url( $url );
116
- return null;
 
117
  }
118
 
119
  function get_urls_from_html( $html ) {
120
  if ( empty( $html ) )
121
  return array();
122
- libxml_use_internal_errors( false );
123
 
124
  // Resolve src-set and shortcodes
125
  $html = do_shortcode( $html );
126
  $html = wp_make_content_images_responsive( $html );
127
 
 
128
  $dom = new DOMDocument();
129
- @$dom->loadHTML( $html ); // mm change
130
  $results = array();
131
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  // IFrames (by Mike Meinz)
133
  $iframes = $dom->getElementsByTagName( 'iframe' );
134
  foreach($iframes as $iframe) {
@@ -138,9 +171,10 @@ class Meow_WPMC_Core {
138
  // Create a new DOM Document to hold iframe
139
  $iframe_doc = new DOMDocument();
140
  // Load the url's contents into the DOM
141
- libxml_use_internal_errors(true); // ignore html formatting problems
142
  $rslt = $iframe_doc->loadHTMLFile( $iframe_src );
143
  libxml_clear_errors();
 
144
  if ( $rslt ) {
145
  // Get the resulting html
146
  $iframe_html = $iframe_doc->saveHTML();
@@ -153,7 +187,9 @@ class Meow_WPMC_Core {
153
  }
154
  }
155
  else {
156
- trigger_error( "Failed to load iframe: " . $iframe_src );
 
 
157
  }
158
  }
159
  }
@@ -187,6 +223,18 @@ class Meow_WPMC_Core {
187
  }
188
  }
189
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  // PDF
191
  preg_match_all( "/((https?:\/\/)?[^\\&\#\[\] \"\?]+\.pdf)/", $html, $res );
192
  if ( !empty( $res ) && isset( $res[1] ) && count( $res[1] ) > 0 ) {
@@ -226,22 +274,23 @@ class Meow_WPMC_Core {
226
  }
227
 
228
  function get_images_from_themes( &$ids, &$urls ) {
229
- global $wpdb;
230
-
231
  // USE CURRENT THEME AND WP API
232
  $ch = get_custom_header();
233
  if ( !empty( $ch ) && !empty( $ch->url ) ) {
234
  array_push( $urls, $this->clean_url( $ch->url ) );
235
  }
 
 
 
236
  if ( !empty( $ch ) && !empty( $ch->attachment_id ) ) {
237
  array_push( $ids, $ch->attachment_id );
238
  }
239
  $cl = get_custom_logo();
240
- if ( !empty( $cl ) ) {
241
  $urls = array_merge( $this->get_urls_from_html( $cl ), $urls );
242
  }
243
  $cd = get_background_image();
244
- if ( !empty( $cd ) ) {
245
  array_push( $urls, $this->clean_url( $cd ) );
246
  }
247
  $photography_hero_image = get_theme_mod( 'photography_hero_image' );
@@ -252,10 +301,20 @@ class Meow_WPMC_Core {
252
  if ( !empty( $author_profile_picture ) ) {
253
  array_push( $ids, $author_profile_picture );
254
  }
 
 
 
 
 
 
 
 
 
 
255
  }
256
 
257
  function log( $data = null, $force = false ) {
258
- if ( !get_option( 'wpmc_debuglogs', false ) && !$force )
259
  return;
260
  $fh = @fopen( trailingslashit( dirname(__FILE__) ) . '/media-cleaner.log', 'a' );
261
  if ( !$fh )
@@ -434,7 +493,7 @@ class Meow_WPMC_Core {
434
 
435
  // Make sure there isn't a media DB entry
436
  if ( $issue->type == 0 ) {
437
- $attachmentid = $this->find_media_id_from_file( $issue->path );
438
  if ( $attachmentid ) {
439
  $this->log( "Issue listed as filesystem but Media {$attachmentid} exists." );
440
  }
@@ -579,7 +638,7 @@ class Meow_WPMC_Core {
579
  $query = "INSERT INTO $table (mediaId, mediaUrl, originType) VALUES ";
580
  foreach( $this->refcache as $key => $value ) {
581
  array_push( $values, $value['id'], $value['url'], $value['type'] );
582
- if ( get_option( 'wpmc_debuglogs', false ) ) {
583
  if ( !empty( $value['id'] ) )
584
  $this->log( "* {$value['type']}: Media #{$value['id']}" );
585
  if ( !empty( $value['url'] ) )
@@ -608,7 +667,7 @@ class Meow_WPMC_Core {
608
  return ($count > 0);
609
  }
610
 
611
- function find_media_id_from_file( $file ) {
612
  global $wpdb;
613
  $postmeta_table_name = $wpdb->prefix . 'postmeta';
614
  $file = $this->clean_uploaded_filename( $file );
@@ -618,11 +677,14 @@ class Meow_WPMC_Core {
618
  AND meta_value = %s", $file
619
  );
620
  $ret = $wpdb->get_var( $sql );
621
- if ( empty( $ret ) )
622
- $this->log( "File $file not found as _wp_attached_file (Library)." );
623
- else {
624
- $this->log( "File $file found as Media $ret." );
 
 
625
  }
 
626
  return $ret;
627
  }
628
 
@@ -674,11 +736,32 @@ class Meow_WPMC_Core {
674
  }
675
 
676
  // From a fullpath to the shortened and cleaned path (for example '2013/02/file.png')
 
 
 
 
 
 
 
 
 
 
 
677
  function clean_uploaded_filename( $fullpath ) {
678
- $basedir = $this->upload_folder['basedir'];
679
- $file = str_replace( $basedir, '', $fullpath );
680
- $file = str_replace( "./", "", $file );
681
- $file = trim( $file, "/" );
 
 
 
 
 
 
 
 
 
 
682
  return $file;
683
  }
684
 
@@ -730,10 +813,7 @@ class Meow_WPMC_Core {
730
  if ( file_exists( $fullpath ) ) {
731
 
732
  // Special scan: Broken only!
733
- $check_postmeta = get_option( 'wpmc_postmeta', false );
734
- $check_posts = get_option( 'wpmc_posts', false );
735
- $check_widgets = get_option( 'wpmc_widgets', false );
736
- if ( !$check_postmeta && !$check_posts && !$check_widgets )
737
  return true;
738
 
739
  $size = filesize( $fullpath );
@@ -833,7 +913,7 @@ class Meow_WPMC_Core {
833
  */
834
 
835
  function wpmc_init( $mainfile ) {
836
- register_activation_hook( $mainfile, 'wpmc_reset' );
837
  //register_deactivation_hook( $mainfile, 'wpmc_uninstall' );
838
  register_uninstall_hook( $mainfile, 'wpmc_uninstall' );
839
  }
@@ -864,9 +944,11 @@ function wpmc_install() {
864
  deleted TINYINT(1) NOT NULL DEFAULT 0,
865
  issue TINYTEXT NOT NULL,
866
  PRIMARY KEY (id)
867
- ) " . $charset_collate . ";";
868
  require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
869
  dbDelta( $sql );
 
 
870
  $table_name = $wpdb->prefix . "mclean_refs";
871
  $charset_collate = $wpdb->get_charset_collate();
872
  // This key doesn't work on too many installs because of the 'Specified key was too long' issue
3
  class Meow_WPMC_Core {
4
 
5
  public $admin = null;
6
+ public $last_analysis = null; //TODO: Is it actually used?
7
+ public $engine = null;
8
+ private $regex_file = '/[A-Za-z0-9-_,.\(\)\s]+[.]{1}(MIMETYPES)/';
9
  public $current_method = 'media';
10
  private $refcache = array();
11
  public $servername = null;
12
  public $upload_folder = null;
13
  public $contentDir = null; // becomes 'wp-content/uploads'
14
+ private $check_postmeta = null;
15
+ private $check_posts = null;
16
+ private $check_widgets = null;
17
+ private $debug_logs = null;
18
+ public $site_url = null;
19
 
20
  public function __construct( $admin ) {
21
  $this->admin = $admin;
22
+ $this->site_url = get_site_url();
23
  $this->current_method = get_option( 'wpmc_method', 'media' );
24
  $types = "jpg|jpeg|jpe|gif|png|tiff|bmp|csv|pdf|xls|xlsx|doc|docx|tiff|mp3|mp4|wav|lua";
25
+ $this->regex_file = str_replace( "MIMETYPES", $types, $this->regex_file );
26
+ $this->servername = str_replace( 'http://', '', str_replace( 'https://', '', $this->site_url ) );
27
  $this->upload_folder = wp_upload_dir();
28
+ $this->contentDir = substr( $this->upload_folder['baseurl'], 1 + strlen( $this->site_url ) );
29
+ $this->check_postmeta = get_option( 'wpmc_postmeta', false );
30
+ $this->check_posts = get_option( 'wpmc_posts', false );
31
+ $this->check_widgets = get_option( 'wpmc_widgets', false );
32
+ $this->debug_logs = get_option( 'wpmc_debuglogs', false );
33
  add_action( 'wpmc_initialize_parsers', array( $this, 'initialize_parsers' ), 10, 0 );
34
+
35
+ require __DIR__ . '/engine.php';
36
+ require __DIR__ . '/ui.php';
37
+ require __DIR__ . '/api.php';
38
+ $this->engine = new Meow_WPMC_Engine( $this, $admin );
39
+ new Meow_WPMC_UI( $this, $admin );
40
+ new Meow_WPMC_API( $this, $admin, $this->engine );
41
  }
42
 
43
  function initialize_parsers() {
125
  }
126
 
127
  function get_favicon() {
128
+ // Yoast SEO plugin
129
  $vals = get_option( 'wpseo_titles' );
130
+ if ( !empty( $vals ) ) {
131
+ $url = $vals['company_logo'];
132
+ if ( $this->is_url( $url ) )
133
+ return $this->clean_url( $url );
134
+ }
135
  }
136
 
137
  function get_urls_from_html( $html ) {
138
  if ( empty( $html ) )
139
  return array();
 
140
 
141
  // Resolve src-set and shortcodes
142
  $html = do_shortcode( $html );
143
  $html = wp_make_content_images_responsive( $html );
144
 
145
+ // Create the DOM Document
146
  $dom = new DOMDocument();
147
+ @$dom->loadHTML( $html );
148
  $results = array();
149
 
150
+ // <meta> tags in <head> area
151
+ $metas = $dom->getElementsByTagName( 'meta' );
152
+ foreach ( $metas as $meta ) {
153
+ $property = $meta->getAttribute( 'property' );
154
+ if ( $property == 'og:image' || $property == 'og:image:secure_url' || $property == 'twitter:image' ) {
155
+ $url = $meta->getAttribute( 'content' );
156
+ if ( $this->is_url( $url ) ) {
157
+ $src = $this->clean_url( $url );
158
+ if ( !empty( $src ) ) {
159
+ array_push( $results, $src );
160
+ }
161
+ }
162
+ }
163
+ }
164
+
165
  // IFrames (by Mike Meinz)
166
  $iframes = $dom->getElementsByTagName( 'iframe' );
167
  foreach($iframes as $iframe) {
171
  // Create a new DOM Document to hold iframe
172
  $iframe_doc = new DOMDocument();
173
  // Load the url's contents into the DOM
174
+ libxml_use_internal_errors( true ); // ignore html formatting problems
175
  $rslt = $iframe_doc->loadHTMLFile( $iframe_src );
176
  libxml_clear_errors();
177
+ libxml_use_internal_errors( false );
178
  if ( $rslt ) {
179
  // Get the resulting html
180
  $iframe_html = $iframe_doc->saveHTML();
187
  }
188
  }
189
  else {
190
+ $err = 'ERROR: Failed to load iframe: ' . $iframe_src;
191
+ error_log( $err );
192
+ $this->core->log( $err );
193
  }
194
  }
195
  }
223
  }
224
  }
225
 
226
+ // <link> tags in <head> area
227
+ $urls = $dom->getElementsByTagName( 'link' );
228
+ foreach ( $urls as $url ) {
229
+ $url_href = $url->getAttribute( 'href' );
230
+ if ( $this->is_url( $url_href ) ) {
231
+ $src = $this->clean_url( $url_href );
232
+ if ( !empty( $src ) ) {
233
+ array_push( $results, $src );
234
+ }
235
+ }
236
+ }
237
+
238
  // PDF
239
  preg_match_all( "/((https?:\/\/)?[^\\&\#\[\] \"\?]+\.pdf)/", $html, $res );
240
  if ( !empty( $res ) && isset( $res[1] ) && count( $res[1] ) > 0 ) {
274
  }
275
 
276
  function get_images_from_themes( &$ids, &$urls ) {
 
 
277
  // USE CURRENT THEME AND WP API
278
  $ch = get_custom_header();
279
  if ( !empty( $ch ) && !empty( $ch->url ) ) {
280
  array_push( $urls, $this->clean_url( $ch->url ) );
281
  }
282
+ if ( $this->is_url( $ch->thumbnail_url ) ) {
283
+ array_push( $urls, $this->clean_url( $ch->thumbnail_url ) );
284
+ }
285
  if ( !empty( $ch ) && !empty( $ch->attachment_id ) ) {
286
  array_push( $ids, $ch->attachment_id );
287
  }
288
  $cl = get_custom_logo();
289
+ if ( $this->is_url( $cl ) ) {
290
  $urls = array_merge( $this->get_urls_from_html( $cl ), $urls );
291
  }
292
  $cd = get_background_image();
293
+ if ( $this->is_url( $cd ) ) {
294
  array_push( $urls, $this->clean_url( $cd ) );
295
  }
296
  $photography_hero_image = get_theme_mod( 'photography_hero_image' );
301
  if ( !empty( $author_profile_picture ) ) {
302
  array_push( $ids, $author_profile_picture );
303
  }
304
+ if ( function_exists ( 'get_uploaded_header_images' ) ) {
305
+ $header_images = get_uploaded_header_images();
306
+ if ( !empty( $header_images ) ) {
307
+ foreach( $header_images as $hi ) {
308
+ if ( !empty ( $hi['attachment_id'] ) ) {
309
+ array_push( $ids, $hi['attachment_id'] );
310
+ }
311
+ }
312
+ }
313
+ }
314
  }
315
 
316
  function log( $data = null, $force = false ) {
317
+ if ( !$this->debug_logs && !$force )
318
  return;
319
  $fh = @fopen( trailingslashit( dirname(__FILE__) ) . '/media-cleaner.log', 'a' );
320
  if ( !$fh )
493
 
494
  // Make sure there isn't a media DB entry
495
  if ( $issue->type == 0 ) {
496
+ $attachmentid = $this->find_media_id_from_file( $issue->path, true );
497
  if ( $attachmentid ) {
498
  $this->log( "Issue listed as filesystem but Media {$attachmentid} exists." );
499
  }
638
  $query = "INSERT INTO $table (mediaId, mediaUrl, originType) VALUES ";
639
  foreach( $this->refcache as $key => $value ) {
640
  array_push( $values, $value['id'], $value['url'], $value['type'] );
641
+ if ( $this->debug_logs ) {
642
  if ( !empty( $value['id'] ) )
643
  $this->log( "* {$value['type']}: Media #{$value['id']}" );
644
  if ( !empty( $value['url'] ) )
667
  return ($count > 0);
668
  }
669
 
670
+ function find_media_id_from_file( $file, $doLog ) {
671
  global $wpdb;
672
  $postmeta_table_name = $wpdb->prefix . 'postmeta';
673
  $file = $this->clean_uploaded_filename( $file );
677
  AND meta_value = %s", $file
678
  );
679
  $ret = $wpdb->get_var( $sql );
680
+ if ( $doLog ) {
681
+ if ( empty( $ret ) )
682
+ $this->log( "File $file not found as _wp_attached_file (Library)." );
683
+ else {
684
+ $this->log( "File $file found as Media $ret." );
685
+ }
686
  }
687
+
688
  return $ret;
689
  }
690
 
736
  }
737
 
738
  // From a fullpath to the shortened and cleaned path (for example '2013/02/file.png')
739
+ // Original version by Jordy
740
+ // function clean_uploaded_filename( $fullpath ) {
741
+ // $basedir = $this->upload_folder['basedir'];
742
+ // $file = str_replace( $basedir, '', $fullpath );
743
+ // $file = str_replace( "./", "", $file );
744
+ // $file = trim( $file, "/" );
745
+ // return $file;
746
+ // }
747
+
748
+ // From a fullpath to the shortened and cleaned path (for example '2013/02/file.png')
749
+ // Faster version, more difficult to read, by Mike Meinz
750
  function clean_uploaded_filename( $fullpath ) {
751
+ $dirIndex = strpos( $fullpath, $this->contentDir );
752
+ if ( $dirIndex == false ) {
753
+ $file = $fullpath;
754
+ }
755
+ else {
756
+ // Remove first part of the path leaving yyyy/mm/filename.ext
757
+ $file = substr( $fullpath, 1 + strlen( $this->contentDir ) + $dirIndex );
758
+ }
759
+ if ( substr( $file, 0, 2 ) == './' ) {
760
+ $file = substr( $file, 2 );
761
+ }
762
+ if ( substr( $file, 0, 1 ) == '/' ) {
763
+ $file = substr( $file, 1 );
764
+ }
765
  return $file;
766
  }
767
 
813
  if ( file_exists( $fullpath ) ) {
814
 
815
  // Special scan: Broken only!
816
+ if ( !$this->check_postmeta && !$this->check_posts && !$this->check_widgets )
 
 
 
817
  return true;
818
 
819
  $size = filesize( $fullpath );
913
  */
914
 
915
  function wpmc_init( $mainfile ) {
916
+ //register_activation_hook( $mainfile, 'wpmc_reset' );
917
  //register_deactivation_hook( $mainfile, 'wpmc_uninstall' );
918
  register_uninstall_hook( $mainfile, 'wpmc_uninstall' );
919
  }
944
  deleted TINYINT(1) NOT NULL DEFAULT 0,
945
  issue TINYTEXT NOT NULL,
946
  PRIMARY KEY (id)
947
+ ) " . $charset_collate . ";" ;
948
  require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
949
  dbDelta( $sql );
950
+ $sql="ALTER TABLE $table_name ADD INDEX IgnoredIndex (ignored) USING BTREE;";
951
+ $wpdb->query($sql);
952
  $table_name = $wpdb->prefix . "mclean_refs";
953
  $charset_collate = $wpdb->get_charset_collate();
954
  // This key doesn't work on too many installs because of the 'Specified key was too long' issue
engine.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Meow_WPMC_Engine {
4
+
5
+ function __construct( $core, $admin ) {
6
+ $this->core = $core;
7
+ $this->admin = $admin;
8
+ }
9
+
10
+ /*
11
+ STEP 1: Parse the content, and look for references
12
+ */
13
+
14
+ // Parse the posts for references (based on $limit and $limitsize for paging the scan)
15
+ function parse( $limit, $limitsize, &$message = '' ) {
16
+ if ( empty( $limit ) )
17
+ $this->core->reset_issues();
18
+
19
+ $method = get_option( 'wpmc_method', 'media' );
20
+ $check_library = get_option(' wpmc_media_library', true );
21
+ $check_postmeta = get_option( 'wpmc_postmeta', false );
22
+ $check_posts = get_option( 'wpmc_posts', false );
23
+ $check_widgets = get_option( 'wpmc_widgets', false );
24
+
25
+ if ( $method == 'media' && !$check_posts && !$check_postmeta && !$check_widgets ) {
26
+ $message = __( "Posts, Meta and Widgets analysis are all off. Done.", 'media-cleaner' );
27
+ return true;
28
+ }
29
+ if ( $method == 'files' && $check_library && !$check_posts && !$check_postmeta && !$check_widgets ) {
30
+ $message = __( "Posts, Meta and Widgets analysis are all off. Done.", 'media-cleaner' );
31
+ return true;
32
+ }
33
+
34
+ // Initialize the parsers
35
+ do_action( 'wpmc_initialize_parsers' );
36
+
37
+ global $wpdb;
38
+ // Maybe we could avoid to check more post_types.
39
+ // SELECT post_type, COUNT(*) FROM `wp_posts` GROUP BY post_type
40
+ $posts = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
41
+ WHERE p.post_status != 'inherit'
42
+ AND p.post_status != 'trash'
43
+ AND p.post_status != 'auto-draft'
44
+ AND p.post_type != 'attachment'
45
+ AND p.post_type != 'shop_order'
46
+ AND p.post_type != 'shop_order_refund'
47
+ AND p.post_type != 'nav_menu_item'
48
+ AND p.post_type != 'revision'
49
+ AND p.post_type != 'auto-draft'
50
+ AND p.post_type != 'wphb_minify_group'
51
+ AND p.post_type != 'customize_changeset'
52
+ AND p.post_type != 'oembed_cache'
53
+ AND p.post_type NOT LIKE 'ml-slide%'
54
+ AND p.post_type NOT LIKE '%acf-%'
55
+ AND p.post_type NOT LIKE '%edd_%'
56
+ LIMIT %d, %d", $limit, $limitsize
57
+ )
58
+ );
59
+
60
+ // Only at the beginning
61
+ if ( empty( $limit ) ) {
62
+ $this->core->log( "Parsed references:" );
63
+ if ( get_option( 'wpmc_widgets', false ) ) {
64
+
65
+ global $wp_registered_widgets;
66
+ $syswidgets = $wp_registered_widgets;
67
+ $active_widgets = get_option( 'sidebars_widgets' );
68
+ foreach ( $active_widgets as $sidebar_name => $widgets ) {
69
+ if ( $sidebar_name != 'wp_inactive_widgets' && !empty( $widgets ) && is_array( $widgets ) ) {
70
+ foreach ( $widgets as $key => $widget ) {
71
+ do_action( 'wpmc_scan_widget', $syswidgets[$widget] );
72
+ }
73
+ }
74
+ }
75
+
76
+ do_action( 'wpmc_scan_widgets' );
77
+ }
78
+ do_action( 'wpmc_scan_once' );
79
+ }
80
+
81
+ $this->core->timeout_check_start( count( $posts ) );
82
+
83
+ foreach ( $posts as $post ) {
84
+ $this->core->timeout_check();
85
+
86
+ // Check Meta
87
+ if ( $check_postmeta )
88
+ do_action( 'wpmc_scan_postmeta', $post );
89
+
90
+ // Check Posts
91
+ if ( $check_posts ) {
92
+ // Get HTML for this post
93
+ $html = get_post_field( 'post_content', $post );
94
+ do_action( 'wpmc_scan_post', $html, $post );
95
+ }
96
+
97
+ // Extra scanning methods
98
+ do_action( 'wpmc_scan_extra', $post );
99
+
100
+ $this->core->timeout_check_additem();
101
+ }
102
+
103
+ // Write the references found (and cached) by the parsers
104
+ $this->core->write_references();
105
+
106
+ $finished = count( $posts ) < $limitsize;
107
+ if ( $finished )
108
+ $this->core->log();
109
+ $message = __( "Posts checked.", 'media-cleaner' );
110
+ return $finished;
111
+ }
112
+
113
+ /*
114
+ STEP 2: List the media entries (or files)
115
+ */
116
+
117
+ // Get files in /uploads (if path is null, the root of /uploads is returned)
118
+ function get_files( $path = null ) {
119
+ $files = apply_filters( 'wpmc_list_uploaded_files', null, $path );
120
+ return $files;
121
+ }
122
+
123
+ function get_media_entries( $limit, $limitsize ) {
124
+ global $wpdb;
125
+ $results = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p
126
+ WHERE p.post_status = 'inherit'
127
+ AND p.post_type = 'attachment'
128
+ LIMIT %d, %d", $limit, $limitsize
129
+ )
130
+ );
131
+ return $results;
132
+ }
133
+
134
+ /*
135
+ STEP 3: Check the media entries (or files) against the references
136
+ */
137
+
138
+ function check_media( $media ) {
139
+ return $this->core->check_media( $media );
140
+ }
141
+
142
+ function check_file( $file ) {
143
+ return apply_filters( 'wpmc_check_file', true, $file );
144
+ }
145
+
146
+ }
147
+
148
+ ?>
media-cleaner.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Media Cleaner
4
  Plugin URI: https://meowapps.com
5
  Description: Clean your Media Library, many options, trash system.
6
- Version: 5.2.1
7
  Author: Jordy Meow
8
  Author URI: https://meowapps.com
9
  Text Domain: media-cleaner
@@ -25,18 +25,14 @@ if ( is_admin() ) {
25
 
26
  global $wpmc_version;
27
  global $wpmc;
28
- $wpmc_version = '5.2.1';
29
 
30
  require __DIR__ . '/admin.php';
31
  require __DIR__ . '/core.php';
32
- require __DIR__ . '/ui.php';
33
- require __DIR__ . '/api.php';
34
 
35
  wpmc_init( __FILE__ );
36
  $admin = new Meow_WPMC_Admin( 'wpmc', __FILE__, 'media-cleaner' );
37
  $wpmc = new Meow_WPMC_Core( $admin );
38
- new Meow_WPMC_UI( $wpmc, $admin );
39
- new Meow_WPMC_API( $wpmc, $admin );
40
  }
41
 
42
  ?>
3
  Plugin Name: Media Cleaner
4
  Plugin URI: https://meowapps.com
5
  Description: Clean your Media Library, many options, trash system.
6
+ Version: 5.2.4
7
  Author: Jordy Meow
8
  Author URI: https://meowapps.com
9
  Text Domain: media-cleaner
25
 
26
  global $wpmc_version;
27
  global $wpmc;
28
+ $wpmc_version = '5.2.4';
29
 
30
  require __DIR__ . '/admin.php';
31
  require __DIR__ . '/core.php';
 
 
32
 
33
  wpmc_init( __FILE__ );
34
  $admin = new Meow_WPMC_Admin( 'wpmc', __FILE__, 'media-cleaner' );
35
  $wpmc = new Meow_WPMC_Core( $admin );
 
 
36
  }
37
 
38
  ?>
parsers.php CHANGED
@@ -13,12 +13,6 @@ class MeowApps_WPMC_Parsers {
13
  if ( class_exists( 'Attachments' ) ) // mm change
14
  require_once( 'parsers/attachments.php' );
15
 
16
- if ( class_exists( 'ACF' ) )
17
- require_once( 'parsers/acf.php' );
18
-
19
- if ( function_exists( 'acfw_globals' ) ) // mm change
20
- require_once( 'parsers/acf_widgets.php' );
21
-
22
  if ( class_exists( 'MetaSliderPlugin' ) || class_exists( 'MetaSliderPro' ) ) // mm change
23
  require_once( 'parsers/metaslider.php' );
24
 
13
  if ( class_exists( 'Attachments' ) ) // mm change
14
  require_once( 'parsers/attachments.php' );
15
 
 
 
 
 
 
 
16
  if ( class_exists( 'MetaSliderPlugin' ) || class_exists( 'MetaSliderPro' ) ) // mm change
17
  require_once( 'parsers/metaslider.php' );
18
 
parsers/acf.php DELETED
@@ -1,94 +0,0 @@
1
- <?php
2
-
3
- add_action( 'wpmc_scan_postmeta', 'wpmc_scan_postmeta_acf' );
4
-
5
- function wpmc_scan_postmeta_acf( $id ) {
6
- $fields = get_field_objects( $id );
7
- if ( is_array( $fields ) ) {
8
- foreach ( $fields as $field )
9
- wpmc_scan_postmeta_acf_field( $field, $id, 8 );
10
- }
11
- }
12
-
13
- /**
14
- * Scans a single ACF field object.
15
- * If the specified field is a repeater or a flexible content,
16
- * scans each subfield recursively.
17
- *
18
- * @param array $field
19
- * An associative array replesenting a single ACF field.
20
- * The actual array must be structured like this:
21
- * array (
22
- * 'name' => The name of the field
23
- * 'type' => The field type i.e. 'text', 'object', 'repeater'
24
- * 'value' => The value
25
- * ...
26
- * )
27
- * @param int $id The post ID
28
- * @param int $recursion_limit The max recursion depth. Negative number means unlimited
29
- *
30
- * @since ACF 5.6.10
31
- */
32
- function wpmc_scan_postmeta_acf_field( $field, $id, $recursion_limit = -1 ) {
33
- if ( !isset( $field['type'] ) ) return;
34
-
35
- global $wpmc;
36
-
37
- /** Multiple Fields (Repeater or Flexible Content) **/
38
- static $recursives = array ( // Possibly Recursive Types
39
- 'repeater',
40
- 'flexible_content'
41
- );
42
- if ( in_array( $field['type'], $recursives ) && have_rows( $field['name'], $id ) ) {
43
- if ( $recursion_limit == 0 ) return; // Too much recursion
44
- do { // Iterate over rows
45
- $row = the_row( true );
46
- foreach ( $row as $col => $value ) { // Iterate over columns (subfields)
47
- $subfield = get_sub_field_object( $col, true, true );
48
- if ( !is_array( $subfield ) ) continue;
49
- if ( WP_DEBUG ) { // XXX Debug
50
- if ( !isset( $subfield['value'] ) ) trigger_error( 'Unexpected Situation: $subfield[value] is not set', E_USER_ERROR );
51
- if ( $subfield['value'] != $value ) trigger_error( 'Unexpected Situation: $subfield[value] has unexpected value', E_USER_ERROR );
52
- }
53
- wpmc_scan_postmeta_acf_field( $subfield, $id, $recursion_limit - 1 ); // Recursion
54
- }
55
- } while ( have_rows( $field['name'], $id ) );
56
- return;
57
- }
58
- /** Singular Field **/
59
- $postmeta_images_acf_ids = array();
60
- $postmeta_images_acf_urls = array();
61
-
62
- $format = "";
63
- if ( isset( $field['return_format'] ) )
64
- $format = $field['return_format'];
65
- else if ( isset( $field['save_format'] ) )
66
- $format = $field['save_format'];
67
-
68
- // ACF Image ID and URL
69
- if ( $field['type'] == 'image' && ( $format == 'array' || $format == 'object' ) ) {
70
- if ( !empty( $field['value']['id'] ) )
71
- array_push( $postmeta_images_acf_ids, $field['value']['id'] );
72
- if ( !empty( $field['value']['url'] ) )
73
- array_push( $postmeta_images_acf_urls, $wpmc->clean_url( $field['value']['url'] ) );
74
- }
75
- // ACF Image ID
76
- else if ( $field['type'] == 'image' && $format == 'id' && !empty( $field['value'] ) ) {
77
- array_push( $postmeta_images_acf_ids, $field['value'] );
78
- }
79
- // ACF Image URL
80
- else if ( $field['type'] == 'image' && $format == 'url' && !empty( $field['value'] ) ) {
81
- array_push( $postmeta_images_acf_urls, $wpmc->clean_url( $field['value'] ) );
82
- }
83
- // ACF Gallery
84
- else if ( $field['type'] == 'gallery' && !empty( $field['value'] ) ) {
85
- foreach ( $field['value'] as $media ) {
86
- if ( !empty( $media['id'] ) )
87
- array_push( $postmeta_images_acf_ids, $media['id'] );
88
- }
89
- }
90
- $wpmc->add_reference_id( $postmeta_images_acf_ids, 'ACF (ID)' );
91
- $wpmc->add_reference_url( $postmeta_images_acf_urls, 'ACF (URL)' );
92
- }
93
-
94
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
parsers/acf_widgets.php DELETED
@@ -1,73 +0,0 @@
1
- <?php
2
-
3
- // ACF Widget plugin
4
- // https://acfwidgets.com
5
- // Added by Mike Meinz
6
-
7
- // Each field is a separate row in the wp_options table
8
-
9
- add_action( 'wpmc_scan_widget', 'wpmc_scan_widget_acf_widgets', 10, 1 );
10
-
11
- function wpmc_scan_widget_acf_widgets( $widget ) {
12
- $acfwidget = $widget['callback'][0]->id;
13
- If ( strlen($acfwidget)>11 && substr($acfwidget,0,11)=='acf_widget_' )
14
- get_images_from_acfwidgets ( $acfwidget );
15
- }
16
-
17
- function get_images_from_acfwidgets( $widget) {
18
- global $wpmc;
19
- global $wpdb;
20
- // $widget starts with: acf_widget_ and looks like this: acf_widget_15011-2
21
- $LikeKey = 'widget_' . $widget . '_%'; // Example: option_name starts with widget_acf_widget_15216-3_
22
- $q = "SELECT option_name, option_value FROM {$wpdb->options} where option_name like %s;";
23
- $OptionRows = $wpdb->get_results( $wpdb->prepare( $q, $LikeKey ) , ARRAY_N );
24
- if ( $wpdb->last_error ) {
25
- error_log( $q . " " . $wpdb->last_error );
26
- $wpmc->log( $q . " " . $wpdb->last_error );
27
- die( $wpdb->last_error );
28
- }
29
- if ( count( $OptionRows ) > 0 ) {
30
- $ACFWidget_ids = array();
31
- $ACFWidget_urls = array();
32
- foreach( $OptionRows as $row ) {
33
- //$row[0] = option_name from wp_options
34
- //$row[1] = option_value from wp_options
35
- // Three if statements in priority order (image ids, link fields, text fields)
36
- // *** An image field containing a post id for the image or is it???
37
- if ( strpos($row[0], 'image') || strpos($row[0], 'icon') !== false ) {
38
- if ( is_numeric( $row[1] ) ) {
39
- array_push( $ACFWidget_ids, $row[1] );
40
- }
41
- }
42
-
43
- // No else here because sometimes image or icon is present in the option_name and link is also present
44
- // Example: widget_acf_widget_15011-2_link_1_link_icon
45
- // Example: widget_acf_widget_15216-3_widget_image_link
46
-
47
- // *** A link field may contain a link or be empty
48
- if ( strpos( $row[0], 'link' ) || strpos( $row[0], 'url' ) !== false ) {
49
- if ( $wpmc->is_url($row[1]) ) {
50
- $url = $wpmc->clean_url($row[1]);
51
- if (!empty($url)) {
52
- array_push($ACFWidget_urls, $url);
53
- }
54
- }
55
- }
56
-
57
- // *** A text field may contain HTML
58
- if (strpos($row[0], 'text') || strpos($row[0], 'html') !== false) {
59
- if (!empty($row[1])) {
60
- $ACFWidget_urls = array_merge($ACFWidget_urls, $wpmc->get_urls_from_html($row[1])); // mm change
61
- }
62
- }
63
- }
64
- if ( !empty( $ACFWidget_ids ) ) { // mm change
65
- $wpmc->add_reference_id( $ACFWidget_ids , 'ACF WIDGET (ID)' );
66
- }
67
- if ( !empty( $ACFWidget_urls ) ) { // mm change
68
- $wpmc->add_reference_url( $ACFWidget_urls , 'ACF WIDGET (URL)' );
69
- }
70
- }
71
- }
72
-
73
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
parsers/common.php CHANGED
@@ -57,6 +57,11 @@ class MeowApps_WPMC_Parser {
57
  $newIds = $widget_data[$instance_id]['ids'];
58
  $ids = array_merge( $ids, $newIds );
59
  }
 
 
 
 
 
60
  }
61
 
62
  public function scan_widget( $widget ) {
57
  $newIds = $widget_data[$instance_id]['ids'];
58
  $ids = array_merge( $ids, $newIds );
59
  }
60
+ // Recent Blog Posts
61
+ if ( !empty( $widget_data[$instance_id]['thumbnail'] ) ) {
62
+ $id = $widget_data[$instance_id]['thumbnail'];
63
+ array_push( $ids, $id );
64
+ }
65
  }
66
 
67
  public function scan_widget( $widget ) {
parsers/metaslider.php CHANGED
@@ -9,7 +9,7 @@ function wpmc_scan_widgets_metaslider() {
9
  FROM {$wpdb->term_relationships}
10
  WHERE object_id > 0
11
  AND term_taxonomy_id
12
- IN (SELECT term_taxonomy_id FROM wp_term_taxonomy WHERE taxonomy = 'ml-slider');";
13
  $imageIds = $wpdb->get_col( $q );
14
  if ( $wpdb->last_error ) {
15
  error_log( $q . " " . $wpdb->last_error );
9
  FROM {$wpdb->term_relationships}
10
  WHERE object_id > 0
11
  AND term_taxonomy_id
12
+ IN (SELECT term_taxonomy_id FROM {$wpdb->term_taxonomy} WHERE taxonomy = 'ml-slider');";
13
  $imageIds = $wpdb->get_col( $q );
14
  if ( $wpdb->last_error ) {
15
  error_log( $q . " " . $wpdb->last_error );
readme.txt CHANGED
@@ -2,42 +2,52 @@
2
  Contributors: TigrouMeow
3
  Tags: clean, delete, file, files, images, image, media, library, upload, acf
4
  Requires at least: 4.8
5
- Tested up to: 5.1
6
  Requires PHP: 7.0
7
- Stable tag: 5.2.1
8
 
9
  Clean your WordPress (broken media, unused media, files). It has its own trash and recovery features. Please read the description.
10
 
11
  == Description ==
12
 
13
- Clean your Media Library from the media which aren't used in any of your posts, gallery and so on. It features an internal trash, moving the files in there temporarily for you to make sure the files aren't actually in used; once checked, you can trash them permanently. **Before using this plugin, make sure you have a proper backup of your files and database. This is the most important step on the usage of this plugin as you can't trust any file deletion tools.** The Pro version of this plugin brings scanning to the /uploads folder and will detect which files aren't registered in the Media Library, not used in your content and so on. Retina images are also detected and supported, shortcodes, HTML in sidebars and of course your posts, pages and all post types.
14
 
15
- A tutorial is available on the official website, here: [Media Cleaner](https://meowapps.com/media-cleaner).
 
 
16
 
17
  === IMPORTANT ===
18
 
19
- This tool is a knife. Do not use it if you don't have any backup, or if you don't know what it does. For backup, I recommend use the excellent service called [BlogVault](https://meow.click/blogvault). Such a plugin is difficult to create and to maintain. If you understand WordPress, you probably know why. This plugin does its best to help you. Learn how to use it and you will get awesome results.
20
 
21
  === DASHBOARD ===
22
- The files detected as not used will be listed in a specific dashboard. At this point, it will be up to you to delete them. They will be then moved to a trash internal to the plugin. After more testing, you can trash them permanently.
 
23
 
24
  === COMPATIBILITY ===
25
- It works with any kind of media, and including their retina and/or WebP versions. I am adding support for specific plugins little by little. As it requires meticulous work and updates, **specific checks for Page Builders are being added to the Pro version**.
26
 
27
- === PRO ===
28
- [Media Cleaner Pro](https://meowapps.com/media-cleaner) can scan your physical /uploads directory, and match it against the Media Library. It also has extra support for plugins which are complicated to handle. Here is the list:
 
29
 
30
- - Gutenberg
31
- - ACF
32
- - Divi
 
33
  - Fusion Builder (Avada)
34
- - WooCommerce
35
  - Visual Composer (WPBakery)
36
  - Elementor
37
  - Beaver Builder
 
38
 
39
  === AGAIN, BE CAREFUL ===
40
- Again, this plugin deletes files so be careful! Backup is not only important, it is **necessary**. Don't use this plugin if you don't understand how WordPress works.
 
 
 
 
 
 
41
 
42
  == Installation ==
43
 
@@ -52,6 +62,15 @@ Again, this plugin deletes files so be careful! Backup is not only important, it
52
 
53
  == Changelog ==
54
 
 
 
 
 
 
 
 
 
 
55
  = 5.2.1 =
56
  * Add: Support for My Calendar (thanks to Mike Meinz).
57
  * Add: Support for iFrames (thanks to Mike Meinz).
@@ -62,7 +81,6 @@ Again, this plugin deletes files so be careful! Backup is not only important, it
62
  * Fix: Filenames with spaces weren't detected correctly and other.
63
  * Fix: Make sure that the shortcodes are resolved.
64
  * Add: Compatibility with more plugins (ACF Widgets, Attachments, Metaslider).
65
- * Info: Mike Meinz is an amazing developer who made a thorough debugging of the whole process, made a lot of corrections, and added support for more plugins. Thanks to him, Media Cleaner is much better!
66
 
67
  = 5.1.3 =
68
  * Add: Support for WebP.
2
  Contributors: TigrouMeow
3
  Tags: clean, delete, file, files, images, image, media, library, upload, acf
4
  Requires at least: 4.8
5
+ Tested up to: 5.2
6
  Requires PHP: 7.0
7
+ Stable tag: 5.2.4
8
 
9
  Clean your WordPress (broken media, unused media, files). It has its own trash and recovery features. Please read the description.
10
 
11
  == Description ==
12
 
13
+ Clean your Media Library from the media which aren't used in any of your posts, gallery and so on. It features an internal trash, moving the files in there temporarily for you to make sure the files aren't actually in used; once checked, you can trash them permanently.
14
 
15
+ **Before using this plugin, make sure you have a proper backup of your install. This step is not optional; it is required. You cannot trust any tools modifying or deleting your files. I recommend using the excellent service called [BlogVault](https://meow.click/blogvault).**
16
+
17
+ For compatibility, Pro version and important information, please read this until the end. Last but not least, it is highly recommended to read the tutorial. It is available on the official website, here: [Media Cleaner](https://meowapps.com/media-cleaner).
18
 
19
  === IMPORTANT ===
20
 
21
+ This tool is a knife. Do not use it if you don't have any backup, or if you don't know what it does. Such a plugin is difficult to create and to maintain. If you understand WordPress, you probably know why. This plugin does its best to help you. Learn how to use it and you will get awesome results. I recommend using the excellent service called [BlogVault](https://meow.click/blogvault) to backup your website.
22
 
23
  === DASHBOARD ===
24
+
25
+ The files detected as not used will be listed in a specific dashboard. At this point, it will be up to you to delete them. They will be then moved to a trash internal to the plugin. After more testing, you can retrieve those files from the trash, or you can delete them permanently.
26
 
27
  === COMPATIBILITY ===
 
28
 
29
+ It works with any kind of media entries, including their retina and/or WebP versions. It is tested on modern WordPress installs (with Gutenberg) as well as older ones, with various themes and by a community of thousands of users. It does support **WooCommerce**. Support for specific plugins is being added little by little. As it requires meticulous a lot of work and testing, **the Pro version might be required if you are using complex plugins to handle the content of your website**.
30
+
31
+ === PRO: Filesystem Analysis and Page Builders ===
32
 
33
+ [Media Cleaner Pro](https://meowapps.com/media-cleaner) can scan your physical /uploads directory, and match it against the Media Library. It also has extra support for complex plugins, such as:
34
+
35
+ - ACF (+ ACF Widgets)
36
+ - Divi Builder
37
  - Fusion Builder (Avada)
 
38
  - Visual Composer (WPBakery)
39
  - Elementor
40
  - Beaver Builder
41
+ - And others (Theme X, ZipList Recipe, ...)
42
 
43
  === AGAIN, BE CAREFUL ===
44
+
45
+ Last but not least, and... again: this plugin deletes files. Be careful! Backup is not only important, it is **necessary**. Don't use this plugin if you don't understand what it does and how WordPress works.
46
+
47
+ === SPECIAL THANKS ===
48
+
49
+ - Mike Meinz, an amazing developer from the US who made a thorough debugging of the whole process, load lot of corrections and optimizations, and added support for more plugins.
50
+ - Satoshi Soma, an excellent Japanese developer who helped me when I needed it the most.
51
 
52
  == Installation ==
53
 
62
 
63
  == Changelog ==
64
 
65
+ = 5.2.4 =
66
+ * Add: Lot of refactoring and optimizations.
67
+ * Add: Support for Theme X, ZipList, and better support for standard websites as well.
68
+ * Add: Yes/No dialog for Reset button.
69
+
70
+ = 5.2.3 =
71
+ * Add: Support for Recent Blog Posts.
72
+ * Add: Additional support for images used by the theme.
73
+
74
  = 5.2.1 =
75
  * Add: Support for My Calendar (thanks to Mike Meinz).
76
  * Add: Support for iFrames (thanks to Mike Meinz).
81
  * Fix: Filenames with spaces weren't detected correctly and other.
82
  * Fix: Make sure that the shortcodes are resolved.
83
  * Add: Compatibility with more plugins (ACF Widgets, Attachments, Metaslider).
 
84
 
85
  = 5.1.3 =
86
  * Add: Support for WebP.
scripts/dashboard.js CHANGED
@@ -682,6 +682,31 @@ function wpmc_open_dialog(content) {
682
  if ($(this).hasClass('disabled')) return;
683
  wpmc_delete_all(true);
684
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
685
  })();
686
 
687
  // Dialog
682
  if ($(this).hasClass('disabled')) return;
683
  wpmc_delete_all(true);
684
  });
685
+
686
+ // Reset Button
687
+ wrap.find('#wpmc_reset').on('click', function (ev) {
688
+ ev.preventDefault();
689
+ var $this = $(this);
690
+ var dialog = wpmc_open_dialog({
691
+ title: "Reset",
692
+ body: "This will reset the Media Cleaner database. All the information related to your trash, your latest scan and ignored entries will be lost. Do you want to continue?",
693
+ append: $('<div class="prompt">')
694
+ .append(
695
+ // Cancel Button
696
+ $('<a class="button cancel" href="#">Cancel</a>').on('click', function (ev) {
697
+ ev.preventDefault();
698
+ dialog.dialog('close');
699
+ })
700
+ ).append(
701
+ // Continue Button
702
+ $('<a class="button button-primary continue" href="#">Continue</a>').on('click', function (ev) {
703
+ ev.preventDefault();
704
+ dialog.dialog('close');
705
+ location.href = $this.attr('href');
706
+ })
707
+ )
708
+ });
709
+ });
710
  })();
711
 
712
  // Dialog
views/menu-screen.php CHANGED
@@ -22,7 +22,7 @@
22
  $items_count = $deleted_count;
23
  $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
24
  FROM $table_name WHERE ignored = 0 AND deleted = 1 AND path LIKE %s
25
- ORDER BY time
26
  DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
27
  }
28
  else if ( $view == 'ignored' ) {
@@ -30,7 +30,7 @@
30
  $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
31
  FROM $table_name
32
  WHERE ignored = 1 AND deleted = 0 AND path LIKE %s
33
- ORDER BY time
34
  DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
35
  }
36
  else {
@@ -38,7 +38,7 @@
38
  $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
39
  FROM $table_name
40
  WHERE ignored = 0 AND deleted = 0 AND path LIKE %s
41
- ORDER BY time
42
  DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
43
  }
44
  ?>
@@ -154,6 +154,12 @@
154
  _e( "<b>This version is not Pro.</b> This plugin is a lot of work so please consider <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a> in order to receive support and to contribute in the evolution of it. Also, <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a> version will also give you the option <b>to scan the physical files in your /uploads folder</b> and extra checks for the common Page Builders.", 'media-cleaner' );
155
  echo "</p></div>";
156
 
 
 
 
 
 
 
157
  if ( function_exists( '_et_core_find_latest' ) ) {
158
  echo "<div class='notice notice-warning'><p>";
159
  _e( "<b>Divi has been detected</b>. The free version might detect the files used by Divi correctly, but its full support is only available in <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a>.", 'media-cleaner' );
22
  $items_count = $deleted_count;
23
  $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
24
  FROM $table_name WHERE ignored = 0 AND deleted = 1 AND path LIKE %s
25
+ ORDER BY path, time
26
  DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
27
  }
28
  else if ( $view == 'ignored' ) {
30
  $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
31
  FROM $table_name
32
  WHERE ignored = 1 AND deleted = 0 AND path LIKE %s
33
+ ORDER BY path, time
34
  DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
35
  }
36
  else {
38
  $items = $wpdb->get_results( $wpdb->prepare( "SELECT id, type, postId, path, size, ignored, deleted, issue
39
  FROM $table_name
40
  WHERE ignored = 0 AND deleted = 0 AND path LIKE %s
41
+ ORDER BY path, time
42
  DESC LIMIT %d, %d", '%' . $s . '%', ( $paged - 1 ) * $posts_per_page, $posts_per_page ), OBJECT );
43
  }
44
  ?>
154
  _e( "<b>This version is not Pro.</b> This plugin is a lot of work so please consider <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a> in order to receive support and to contribute in the evolution of it. Also, <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a> version will also give you the option <b>to scan the physical files in your /uploads folder</b> and extra checks for the common Page Builders.", 'media-cleaner' );
155
  echo "</p></div>";
156
 
157
+ if ( class_exists( 'ACF' ) ) {
158
+ echo "<div class='notice notice-warning'><p>";
159
+ _e( "<b>ACF has been detected</b>. The free version might detect the files used by ACF correctly, but its full support is only available in <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a>.", 'media-cleaner' );
160
+ echo "</p></div>";
161
+ }
162
+
163
  if ( function_exists( '_et_core_find_latest' ) ) {
164
  echo "<div class='notice notice-warning'><p>";
165
  _e( "<b>Divi has been detected</b>. The free version might detect the files used by Divi correctly, but its full support is only available in <a target='_blank' href='//meowapps.com/media-cleaner'>Media Cleaner Pro</a>.", 'media-cleaner' );